| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.validate.writing_validators">
- <title>Writing Validators</title>
- <para>
- <classname>Zend_Validate</classname> supplies a set of commonly needed validators, but
- inevitably, developers will wish to write custom validators for their particular needs. The
- task of writing a custom validator is described in this section.
- </para>
- <para>
- <classname>Zend_Validate_Interface</classname> defines two methods,
- <methodname>isValid()</methodname> and <methodname>getMessages()</methodname>, that may
- be implemented by user classes in order to create custom validation objects. An object that
- implements <classname>Zend_Validate_Interface</classname> interface may be added to a
- validator chain with <methodname>Zend_Validate::addValidator()</methodname>. Such objects
- may also be used with <link
- linkend="zend.filter.input"><classname>Zend_Filter_Input</classname></link>.
- </para>
- <para>
- As you may already have inferred from the above description of
- <classname>Zend_Validate_Interface</classname>, validation classes provided with Zend
- Framework return a boolean value for whether or not a value validates successfully. They
- also provide information about <emphasis>why</emphasis> a value failed validation. The
- availability of the reasons for validation failures may be valuable to an application for
- various purposes, such as providing statistics for usability analysis.
- </para>
- <para>
- Basic validation failure message functionality is implemented in
- <classname>Zend_Validate_Abstract</classname>. To include this functionality when creating a
- validation class, simply extend <classname>Zend_Validate_Abstract</classname>. In the
- extending class you would implement the <methodname>isValid()</methodname> method logic and
- define the message variables and message templates that correspond to the types of
- validation failures that can occur. If a value fails your validation tests, then
- <methodname>isValid()</methodname> should return <constant>FALSE</constant>. If the value
- passes your validation tests, then <methodname>isValid()</methodname> should return
- <constant>TRUE</constant>.
- </para>
- <para>
- In general, the <methodname>isValid()</methodname> method should not throw any exceptions,
- except where it is impossible to determine whether or not the input value is valid. A few
- examples of reasonable cases for throwing an exception might be if a file cannot be opened,
- an <acronym>LDAP</acronym> server could not be contacted, or a database connection is
- unavailable, where such a thing may be required for validation success or failure to be
- determined.
- </para>
- <example id="zend.validate.writing_validators.example.simple">
- <title>Creating a Simple Validation Class</title>
- <para>
- The following example demonstrates how a very simple custom validator might be written.
- In this case the validation rules are simply that the input value must be a floating
- point value.
- </para>
- <programlisting language="php"><![CDATA[
- class MyValid_Float extends Zend_Validate_Abstract
- {
- const FLOAT = 'float';
- protected $_messageTemplates = array(
- self::FLOAT => "'%value%' is not a floating point value"
- );
- public function isValid($value)
- {
- $this->_setValue($value);
- if (!is_float($value)) {
- $this->_error(self::FLOAT);
- return false;
- }
- return true;
- }
- }
- ]]></programlisting>
- <para>
- The class defines a template for its single validation failure message, which includes
- the built-in magic parameter, <emphasis>%value%</emphasis>. The call to
- <methodname>_setValue()</methodname> prepares the object to insert the tested value into
- the failure message automatically, should the value fail validation. The call to
- <methodname>_error()</methodname> tracks a reason for validation failure.
- </para>
- </example>
- <example id="zend.validate.writing_validators.example.conditions.dependent">
- <title>Writing a Validation Class having Dependent Conditions</title>
- <para>
- The following example demonstrates a more complex set of validation rules, where it is
- required that the input value be numeric and within the range of minimum and maximum
- boundary values. An input value would fail validation for exactly one of the following
- reasons:
- </para>
- <itemizedlist>
- <listitem>
- <para>The input value is not numeric.</para>
- </listitem>
- <listitem>
- <para>The input value is less than the minimum allowed value.</para>
- </listitem>
- <listitem>
- <para>The input value is more than the maximum allowed value.</para>
- </listitem>
- </itemizedlist>
- <para>
- These validation failure reasons are then translated to definitions in the class:
- </para>
- <programlisting language="php"><![CDATA[
- class MyValid_NumericBetween extends Zend_Validate_Abstract
- {
- const MSG_NUMERIC = 'msgNumeric';
- const MSG_MINIMUM = 'msgMinimum';
- const MSG_MAXIMUM = 'msgMaximum';
- public $minimum = 0;
- public $maximum = 100;
- protected $_messageVariables = array(
- 'min' => 'minimum',
- 'max' => 'maximum'
- );
- protected $_messageTemplates = array(
- self::MSG_NUMERIC => "'%value%' is not numeric",
- self::MSG_MINIMUM => "'%value%' must be at least '%min%'",
- self::MSG_MAXIMUM => "'%value%' must be no more than '%max%'"
- );
- public function isValid($value)
- {
- $this->_setValue($value);
- if (!is_numeric($value)) {
- $this->_error(self::MSG_NUMERIC);
- return false;
- }
- if ($value < $this->minimum) {
- $this->_error(self::MSG_MINIMUM);
- return false;
- }
- if ($value > $this->maximum) {
- $this->_error(self::MSG_MAXIMUM);
- return false;
- }
- return true;
- }
- }
- ]]></programlisting>
- <para>
- The public properties <varname>$minimum</varname> and <varname>$maximum</varname> have
- been established to provide the minimum and maximum boundaries, respectively, for a
- value to successfully validate. The class also defines two message variables that
- correspond to the public properties and allow <property>min</property> and
- <property>max</property> to be used in message templates as magic parameters, just as
- with <property>value</property>.
- </para>
- <para>
- Note that if any one of the validation checks in <methodname>isValid()</methodname>
- fails, an appropriate failure message is prepared, and the method immediately returns
- <constant>FALSE</constant>. These validation rules are therefore sequentially dependent.
- That is, if one test should fail, there is no need to test any subsequent validation
- rules. This need not be the case, however. The following example illustrates how to
- write a class having independent validation rules, where the validation object may
- return multiple reasons why a particular validation attempt failed.
- </para>
- </example>
- <example id="zend.validate.writing_validators.example.conditions.independent">
- <title>Validation with Independent Conditions, Multiple Reasons for Failure</title>
- <para>
- Consider writing a validation class for password strength enforcement - when a user is
- required to choose a password that meets certain criteria for helping secure user
- accounts. Let us assume that the password security criteria enforce that the password:
- </para>
- <itemizedlist>
- <listitem><para>is at least 8 characters in length,</para></listitem>
- <listitem><para>contains at least one uppercase letter,</para></listitem>
- <listitem><para>contains at least one lowercase letter,</para></listitem>
- <listitem><para>and contains at least one digit character.</para></listitem>
- </itemizedlist>
- <para>
- The following class implements these validation criteria:
- </para>
- <programlisting language="php"><![CDATA[
- class MyValid_PasswordStrength extends Zend_Validate_Abstract
- {
- const LENGTH = 'length';
- const UPPER = 'upper';
- const LOWER = 'lower';
- const DIGIT = 'digit';
- protected $_messageTemplates = array(
- self::LENGTH => "'%value%' must be at least 8 characters in length",
- self::UPPER => "'%value%' must contain at least one uppercase letter",
- self::LOWER => "'%value%' must contain at least one lowercase letter",
- self::DIGIT => "'%value%' must contain at least one digit character"
- );
- public function isValid($value)
- {
- $this->_setValue($value);
- $isValid = true;
- if (strlen($value) < 8) {
- $this->_error(self::LENGTH);
- $isValid = false;
- }
- if (!preg_match('/[A-Z]/', $value)) {
- $this->_error(self::UPPER);
- $isValid = false;
- }
- if (!preg_match('/[a-z]/', $value)) {
- $this->_error(self::LOWER);
- $isValid = false;
- }
- if (!preg_match('/\d/', $value)) {
- $this->_error(self::DIGIT);
- $isValid = false;
- }
- return $isValid;
- }
- }
- ]]></programlisting>
- <para>
- Note that the four criteria tests in <methodname>isValid()</methodname> do not
- immediately return <constant>FALSE</constant>. This allows the validation class to
- provide <emphasis>all</emphasis> of the reasons that the input password failed to meet
- the validation requirements. if, for example, a user were to input the string "#$%" as a
- password, <methodname>isValid()</methodname> would cause all four validation failure
- messages to be returned by a subsequent call to <methodname>getMessages()</methodname>.
- </para>
- </example>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|