[ZF-10089] Zend_Log
[zend.git] / documentation / manual / en / module_specs / Zend_Validate-WritingValidators.xml
blob0dab0eaac3df7b7d6ab2267850558b7a0d63f25a
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.validate.writing_validators">
4     <title>Writing Validators</title>
6     <para>
7         <classname>Zend_Validate</classname> supplies a set of commonly needed validators, but
8         inevitably, developers will wish to write custom validators for their particular needs. The
9         task of writing a custom validator is described in this section.
10     </para>
12     <para>
13         <classname>Zend_Validate_Interface</classname> defines two methods,
14         <methodname>isValid()</methodname> and <methodname>getMessages()</methodname>, that may
15         be implemented by user classes in order to create custom validation objects. An object that
16         implements <classname>Zend_Validate_Interface</classname> interface may be added to a
17         validator chain with <methodname>Zend_Validate::addValidator()</methodname>. Such objects
18         may also be used with <link
19             linkend="zend.filter.input"><classname>Zend_Filter_Input</classname></link>.
20     </para>
22     <para>
23         As you may already have inferred from the above description of
24         <classname>Zend_Validate_Interface</classname>, validation classes provided with Zend
25         Framework return a boolean value for whether or not a value validates successfully. They
26         also provide information about <emphasis>why</emphasis> a value failed validation. The
27         availability of the reasons for validation failures may be valuable to an application for
28         various purposes, such as providing statistics for usability analysis.
29     </para>
31     <para>
32         Basic validation failure message functionality is implemented in
33         <classname>Zend_Validate_Abstract</classname>. To include this functionality when creating a
34         validation class, simply extend <classname>Zend_Validate_Abstract</classname>. In the
35         extending class you would implement the <methodname>isValid()</methodname> method logic and
36         define the message variables and message templates that correspond to the types of
37         validation failures that can occur. If a value fails your validation tests, then
38         <methodname>isValid()</methodname> should return <constant>FALSE</constant>. If the value
39         passes your validation tests, then <methodname>isValid()</methodname> should return
40         <constant>TRUE</constant>.
41     </para>
43     <para>
44         In general, the <methodname>isValid()</methodname> method should not throw any exceptions,
45         except where it is impossible to determine whether or not the input value is valid. A few
46         examples of reasonable cases for throwing an exception might be if a file cannot be opened,
47         an <acronym>LDAP</acronym> server could not be contacted, or a database connection is
48         unavailable, where such a thing may be required for validation success or failure to be
49         determined.
50     </para>
52     <example id="zend.validate.writing_validators.example.simple">
53         <title>Creating a Simple Validation Class</title>
55         <para>
56             The following example demonstrates how a very simple custom validator might be written.
57             In this case the validation rules are simply that the input value must be a floating
58             point value.
59         </para>
61         <programlisting language="php"><![CDATA[
62 class MyValid_Float extends Zend_Validate_Abstract
64     const FLOAT = 'float';
66     protected $_messageTemplates = array(
67         self::FLOAT => "'%value%' is not a floating point value"
68     );
70     public function isValid($value)
71     {
72         $this->_setValue($value);
74         if (!is_float($value)) {
75             $this->_error();
76             return false;
77         }
79         return true;
80     }
82 ]]></programlisting>
84         <para>
85             The class defines a template for its single validation failure message, which includes
86             the built-in magic parameter, <emphasis>%value%</emphasis>. The call to
87             <methodname>_setValue()</methodname> prepares the object to insert the tested value into
88             the failure message automatically, should the value fail validation. The call to
89             <methodname>_error()</methodname> tracks a reason for validation failure. Since this
90             class only defines one failure message, it is not necessary to provide
91             <methodname>_error()</methodname> with the name of the failure message template.
92         </para>
93     </example>
95     <example id="zend.validate.writing_validators.example.conditions.dependent">
96         <title>Writing a Validation Class having Dependent Conditions</title>
98         <para>
99             The following example demonstrates a more complex set of validation rules, where it is
100             required that the input value be numeric and within the range of minimum and maximum
101             boundary values. An input value would fail validation for exactly one of the following
102             reasons:
103         </para>
105         <itemizedlist>
106             <listitem>
107                 <para>The input value is not numeric.</para>
108             </listitem>
110             <listitem>
111                 <para>The input value is less than the minimum allowed value.</para>
112             </listitem>
114             <listitem>
115                 <para>The input value is more than the maximum allowed value.</para>
116             </listitem>
117         </itemizedlist>
119         <para>
120             These validation failure reasons are then translated to definitions in the class:
121         </para>
123         <programlisting language="php"><![CDATA[
124 class MyValid_NumericBetween extends Zend_Validate_Abstract
126     const MSG_NUMERIC = 'msgNumeric';
127     const MSG_MINIMUM = 'msgMinimum';
128     const MSG_MAXIMUM = 'msgMaximum';
130     public $minimum = 0;
131     public $maximum = 100;
133     protected $_messageVariables = array(
134         'min' => 'minimum',
135         'max' => 'maximum'
136     );
138     protected $_messageTemplates = array(
139         self::MSG_NUMERIC => "'%value%' is not numeric",
140         self::MSG_MINIMUM => "'%value%' must be at least '%min%'",
141         self::MSG_MAXIMUM => "'%value%' must be no more than '%max%'"
142     );
144     public function isValid($value)
145     {
146         $this->_setValue($value);
148         if (!is_numeric($value)) {
149             $this->_error(self::MSG_NUMERIC);
150             return false;
151         }
153         if ($value < $this->minimum) {
154             $this->_error(self::MSG_MINIMUM);
155             return false;
156         }
158         if ($value > $this->maximum) {
159             $this->_error(self::MSG_MAXIMUM);
160             return false;
161         }
163         return true;
164     }
166 ]]></programlisting>
168         <para>
169             The public properties <varname>$minimum</varname> and <varname>$maximum</varname> have
170             been established to provide the minimum and maximum boundaries, respectively, for a
171             value to successfully validate. The class also defines two message variables that
172             correspond to the public properties and allow <property>min</property> and
173             <property>max</property> to be used in message templates as magic parameters, just as
174             with <property>value</property>.
175         </para>
177         <para>
178             Note that if any one of the validation checks in <methodname>isValid()</methodname>
179             fails, an appropriate failure message is prepared, and the method immediately returns
180             <constant>FALSE</constant>. These validation rules are therefore sequentially dependent.
181             That is, if one test should fail, there is no need to test any subsequent validation
182             rules. This need not be the case, however. The following example illustrates how to
183             write a class having independent validation rules, where the validation object may
184             return multiple reasons why a particular validation attempt failed.
185         </para>
186     </example>
188     <example id="zend.validate.writing_validators.example.conditions.independent">
189         <title>Validation with Independent Conditions, Multiple Reasons for Failure</title>
191         <para>
192             Consider writing a validation class for password strength enforcement - when a user is
193             required to choose a password that meets certain criteria for helping secure user
194             accounts. Let us assume that the password security criteria enforce that the password:
195         </para>
197         <itemizedlist>
198             <listitem><para>is at least 8 characters in length,</para></listitem>
199             <listitem><para>contains at least one uppercase letter,</para></listitem>
200             <listitem><para>contains at least one lowercase letter,</para></listitem>
201             <listitem><para>and contains at least one digit character.</para></listitem>
202         </itemizedlist>
204         <para>
205             The following class implements these validation criteria:
206         </para>
208         <programlisting language="php"><![CDATA[
209 class MyValid_PasswordStrength extends Zend_Validate_Abstract
211     const LENGTH = 'length';
212     const UPPER  = 'upper';
213     const LOWER  = 'lower';
214     const DIGIT  = 'digit';
216     protected $_messageTemplates = array(
217         self::LENGTH => "'%value%' must be at least 8 characters in length",
218         self::UPPER  => "'%value%' must contain at least one uppercase letter",
219         self::LOWER  => "'%value%' must contain at least one lowercase letter",
220         self::DIGIT  => "'%value%' must contain at least one digit character"
221     );
223     public function isValid($value)
224     {
225         $this->_setValue($value);
227         $isValid = true;
229         if (strlen($value) < 8) {
230             $this->_error(self::LENGTH);
231             $isValid = false;
232         }
234         if (!preg_match('/[A-Z]/', $value)) {
235             $this->_error(self::UPPER);
236             $isValid = false;
237         }
239         if (!preg_match('/[a-z]/', $value)) {
240             $this->_error(self::LOWER);
241             $isValid = false;
242         }
244         if (!preg_match('/\d/', $value)) {
245             $this->_error(self::DIGIT);
246             $isValid = false;
247         }
249         return $isValid;
250     }
252 ]]></programlisting>
254         <para>
255             Note that the four criteria tests in <methodname>isValid()</methodname> do not
256             immediately return <constant>FALSE</constant>. This allows the validation class to
257             provide <emphasis>all</emphasis> of the reasons that the input password failed to meet
258             the validation requirements. if, for example, a user were to input the string "#$%" as a
259             password, <methodname>isValid()</methodname> would cause all four validation failure
260             messages to be returned by a subsequent call to <methodname>getMessages()</methodname>.
261         </para>
262     </example>
263 </sect1>
264 <!--
265 vim:se ts=4 sw=4 et: