1 <?xml version="1.0" encoding="UTF-8"?>
3 <!-- EN-Revision: 20799 -->
4 <sect1 id="zend.validate.writing_validators">
6 <title>バリデータの書き方</title>
9 <classname>Zend_Validate</classname> には、よく使うバリデータ群が付属しています。しかし、
10 特定の目的のために使用する独自のバリデータを書くことは避けられないでしょう。
11 ここでは、独自のバリデータを書く方法について説明します。
15 <classname>Zend_Validate_Interface</classname> では、2つのメソッド <methodname>isValid()</methodname>、
16 および <methodname>getMessages()</methodname>
17 を定義しています。これらを自分のクラスで実装して
18 独自のバリデーションオブジェクトを作成します。
19 <classname>Zend_Validate_Interface</classname> を実装したクラスは、
20 <methodname>Zend_Validate::addValidator()</methodname>
23 <link linkend="zend.filter.input"><classname>Zend_Filter_Input</classname></link>
28 上の <classname>Zend_Validate_Interface</classname> についての説明からも推測できるように、
29 Zend Framework が提供しているバリデーションクラスの返り値は、
30 検証に成功したか失敗したかを表す boolean 値となります。また、<emphasis>なぜ</emphasis>
31 検証が失敗したのかについての情報も提供します。この理由がわかると、
32 アプリケーション側で何かと便利です。たとえば、ユーザビリティ改善のための統計情報として利用することなどができます。
36 基本的な検証失敗メッセージ機能を実装しているのが <classname>Zend_Validate_Abstract</classname> です。
37 バリデーションクラスを作成する際にこの機能を組み込むには、
38 <classname>Zend_Validate_Abstract</classname> を継承します。
39 継承したクラス内で <methodname>isValid()</methodname> メソッドのロジックを実装し、
40 発生しうる失敗の形式に対応したメッセージ変数とメッセージテンプレートを定義します。
41 検証に失敗した場合には <methodname>isValid()</methodname> は <constant>FALSE</constant>
42 を返さなければなりません。検証を通過した場合は、<methodname>isValid()</methodname>
43 は <constant>TRUE</constant> を返さなければなりません。
47 一般に、<methodname>isValid()</methodname> メソッドは例外をスローすべきではありません。
48 例外をスローするのは、入力値が妥当かそうでないかの判断ができない場合のみとします。
49 例外をスローすることになる場面としては、たとえばファイルのオープンに失敗したり
50 <acronym>LDAP</acronym> サーバとの接続に失敗したり、データベースとの接続に失敗したり
51 といった原因で入力値が正しいのかどうかが判断できない場合が考えられます。
54 <example id="zend.validate.writing_validators.example.simple">
56 <title>単純なバリデーションクラスの作成</title>
59 次の例は、非常に単純なバリデータの書き方を説明するものです。
60 ここで定義している検証規則は非常に単純で、入力値が浮動小数点値かどうかのみを調べています。
63 <programlisting language="php"><![CDATA[
64 class MyValid_Float extends Zend_Validate_Abstract
66 const FLOAT = 'float';
68 protected $_messageTemplates = array(
69 self::FLOAT => "'%value%' は浮動小数点値ではありません"
72 public function isValid($value)
74 $this->_setValue($value);
76 if (!is_float($value)) {
87 このクラス内には、検証が失敗したときのメッセージ用のテンプレートがひとつ定義されており、
88 その中では組み込みのマジックパラメータ <emphasis>%value%</emphasis> を使用しています。
89 <methodname>_setValue()</methodname> のコールによって、検証した値をこのメッセージに自動的に格納します。
90 これにより、検証に失敗したときに、この値をメッセージに含められるようになります。
91 <methodname>_error()</methodname> のコールによって、検証に失敗した原因を取得します。
92 このクラスでは失敗時のメッセージをひとつしか用意していないので、
93 <methodname>_error()</methodname> でメッセージテンプレートの名前を指定する必要はありません。
98 <example id="zend.validate.writing_validators.example.conditions.dependent">
100 <title>依存条件を伴うバリデーションクラスの作成</title>
103 次の例は、複数の検証規則を組み合わせた複雑なものとなります。
104 ここでは、まず入力値が数値であること、そして指定した最小値と最大値の間にあることを調べます。
105 以下のいずれかが発生したときに、検証は失敗します。
110 <para>入力値が数値ではない</para>
114 <para>入力値が最小値より小さい</para>
118 <para>入力値が最大値より大きい</para>
123 これらの原因に応じて、クラス内でメッセージへの変換が行われます。
126 <programlisting language="php"><![CDATA[
127 class MyValid_NumericBetween extends Zend_Validate_Abstract
129 const MSG_NUMERIC = 'msgNumeric';
130 const MSG_MINIMUM = 'msgMinimum';
131 const MSG_MAXIMUM = 'msgMaximum';
134 public $maximum = 100;
136 protected $_messageVariables = array(
141 protected $_messageTemplates = array(
142 self::MSG_NUMERIC => "'%value%' は数値ではありません",
143 self::MSG_MINIMUM => "'%value%' は '%min%' 以上でなければなりません",
144 self::MSG_MAXIMUM => "'%value%' は '%max%' 以下でなければなりません"
147 public function isValid($value)
149 $this->_setValue($value);
151 if (!is_numeric($value)) {
152 $this->_error(self::MSG_NUMERIC);
156 if ($value < $this->minimum) {
157 $this->_error(self::MSG_MINIMUM);
161 if ($value > $this->maximum) {
162 $this->_error(self::MSG_MAXIMUM);
172 パブリックプロパティ <code>$minimum</code> および <code>$maximum</code>
173 でそれぞれ最小値と最大値を定義し、値がこの間にあった場合に検証が成功したことにしています。
174 このクラスではまた、それぞれのパブリックプロパティに対応するふたつのメッセージ変数を定義しています。
175 そしてメッセージテンプレートの中で <property>value</property> と同様に使えるマジックパラメータとして
176 <property>min</property> および <property>max</property> も用意しています。
180 <methodname>isValid()</methodname> での妥当性チェックのいずれかが失敗すると、
181 適切なメッセージを準備して即時に <constant>FALSE</constant> を返すことに注意しましょう。
182 つまり、これらの検証は、その並び順に依存します。
183 どれかひとつのチェックが失敗すると、それ以降の検証規則を確認する必要はなくなるからです。
184 しかし、時にはこのような処理が不要な場合もあります。
185 次の例は、個々の検証規則を独立させたクラスを書く方法を示すものです。
186 このバリデーションオブジェクトは、検証に失敗したときに複数の理由を返すことがあります。
191 <example id="zend.validate.writing_validators.example.conditions.independent">
193 <title>個々に独立した条件による検証を行い、失敗時に複数の原因を返す</title>
196 パスワードの強度を確認するバリデーションクラスを書くことを考えてみましょう。
197 ユーザに対して、安全なユーザアカウントを発行するために
198 ある条件を満たしたパスワードを設定してもらう際に使用するものです。
199 パスワードの条件としては、次のようなものを前提とします。
203 <listitem><para>最低 8 文字以上であること</para></listitem>
204 <listitem><para>最低ひとつの大文字を含むこと</para></listitem>
205 <listitem><para>最低ひとつの小文字を含むこと</para></listitem>
206 <listitem><para>最低ひとつの数字を含むこと</para></listitem>
210 この検証規則を実装したクラスは、次のようになります。
213 <programlisting language="php"><![CDATA[
214 class MyValid_PasswordStrength extends Zend_Validate_Abstract
216 const LENGTH = 'length';
217 const UPPER = 'upper';
218 const LOWER = 'lower';
219 const DIGIT = 'digit';
221 protected $_messageTemplates = array(
222 self::LENGTH => "'%value%' は少なくとも 8 文字以上でなければなりません",
223 self::UPPER => "'%value%' には最低ひとつの大文字が必要です",
224 self::LOWER => "'%value%' には最低ひとつの小文字が必要です",
225 self::DIGIT => "'%value%' には最低ひとつの数字が必要です"
228 public function isValid($value)
230 $this->_setValue($value);
234 if (strlen($value) < 8) {
235 $this->_error(self::LENGTH);
239 if (!preg_match('/[A-Z]/', $value)) {
240 $this->_error(self::UPPER);
244 if (!preg_match('/[a-z]/', $value)) {
245 $this->_error(self::LOWER);
249 if (!preg_match('/\d/', $value)) {
250 $this->_error(self::DIGIT);
260 <methodname>isValid()</methodname> では四つのチェックを行っていますが、
261 チェックに失敗してもその場では <constant>FALSE</constant> を返していないことに注目しましょう。
262 これにより、入力されたパスワードが満たしていない条件を <emphasis>すべて</emphasis>
263 示すことができるようになります。たとえば、パスワードとして入力された値が
264 "#$%" だったとすると、<methodname>isValid()</methodname>
265 は四つのメッセージをすべて作成し、後で <methodname>getMessages()</methodname>
266 をコールした際にすべて取得できるようになります。