1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.validate.writing_validators">
5 <title>Написание валидаторов</title>
8 <classname>Zend_Validate</classname> предоставляет набор наиболее
9 часто используемых валидаторов, но разработчики часто сталкиваются
10 с такими ситуациями, когда требуется написание своих валидаторов.
11 В этом разделе описан процесс написания своих валидаторов.
15 <classname>Zend_Validate_Interface</classname> определяет три метода:
16 <code>isValid()</code>, <code>getMessages()</code> и
17 <code>getErrors()</code>, они должны
18 реализовываться в ваших классах валидации.
19 Объект, реализующий данный интерфейс, может быть добавлен в цепочку
20 валидаторов через метод <code>Zend_Validate::addValidator()</code>,
21 также такие объекты могут использоваться с классом
22 <link linkend="zend.filter.input"><classname>Zend_Filter_Input</classname></link>.
26 Как вы наверное уже поняли из приведенного выше описания
27 интерфейса <classname>Zend_Validate_Interface</classname>,
28 классы валидации, предоставляемые Zend Framework, возвращают
29 булево значение, означающее успех/неуспех валидации.
30 Они также предоставляют информацию о том
31 <emphasis>почему</emphasis> переданное значение не прошло
32 валидацию. Возможность узнать причину того, почему значение не проходит
33 валидацию, может быть полезна для различных целей, как, например,
34 создание статистики для анализа удобства использования приложения.
38 Базовый функционал для сообщений об ошибке валидации реализован в
39 классе <classname>Zend_Validate_Abstract</classname>.
40 Для того, чтобы использовать этот функционал при создании класса
41 валидации, просто наследуйте свой класс от
42 <classname>Zend_Validate_Abstract</classname>.
43 В классе-наследнике вы можете реализовать логику метода
44 <code>isValid()</code>, а также определить шаблоны и переменные
45 сообщений, которые соответствуют различным типам ошибок валидации.
46 Если значение не проходит проверку, то <code>isValid()</code> должен
47 возвращать <constant>FALSE</constant>. Если значение проходит проверку, то
48 <code>isValid()</code> должен возвращать <constant>TRUE</constant>.
52 Обычно метод <code>isValid()</code> не должен бросать никаких
53 исключений, за исключением тех ситуаций, когда невозможно определить,
54 является ли валидным входное значение или нет.
55 Например, бросок исключения уместен в случае,
56 когда невозможно открыть файл (недоступен сервер LDAP,
57 нет соединения с базой данных), и процесс валидации не может быть
61 <example id="zend.validate.writing_validators.example.simple">
63 <title>Создание простого класса валидации</title>
66 Следующий пример демонстрирует создание простейшего валидатора.
67 В данном случае правила валидации просты - входное значение
68 должно иметь тип <code>float</code>.
70 <programlisting language="php"><![CDATA[
71 class MyValid_Float extends Zend_Validate_Abstract
73 const FLOAT = 'float';
75 protected $_messageTemplates = array(
76 self::FLOAT => "'%value%' не является числом с плавающей точкой"
79 public function isValid($value)
81 $this->_setValue($value);
83 if (!is_float($value)) {
93 В данном классе определен шаблон для единственного сообщения
94 об ошибке валидации, который включает в себя встроенный "магический"
95 параметр <code>%value%</code>.
96 Вызов <code>_setValue()</code> подготавливает объект к подстановке
97 проверяемого значения в сообщение об ошибке.
98 Вызов <code>_error()</code> устанавливает причину ошибки валидации.
99 Поскольку в этом классе только одно сообщение об ошибке,
100 то нет необходимости передавать методу <code>_error()</code>
101 имя шаблона сообщения об ошибке.
106 <example id="zend.validate.writing_validators.example.conditions.dependent">
108 <title>Написание классов валидации с подчиненными условиями</title>
111 Следующий пример демонстрирует более сложный набор правил валидации,
112 где требуется, чтобы входное значение было числом, находящимся
113 в диапазоне между минимальным и максимальным значениями.
114 Значение может не пройти валидацию по одной из следующих причин:
118 <para>Значение не является числом.</para>
121 <para>Значение меньше минимально допустимого.</para>
124 <para>Значение больше максимально допустимого.</para>
130 Эти возможные причины переводятся в определения в классе:
132 <programlisting language="php"><![CDATA[
133 class MyValid_NumericBetween extends Zend_Validate_Abstract
135 const MSG_NUMERIC = 'msgNumeric';
136 const MSG_MINIMUM = 'msgMinimum';
137 const MSG_MAXIMUM = 'msgMaximum';
140 public $maximum = 100;
142 protected $_messageVariables = array(
147 protected $_messageTemplates = array(
148 self::MSG_NUMERIC => "'%value%' не является числом",
149 self::MSG_MINIMUM => "'%value%' должен быть не меньше '%min%'",
150 self::MSG_MAXIMUM => "'%value%' должен быть не больше '%max%'"
153 public function isValid($value)
155 $this->_setValue($value);
157 if (!is_numeric($value)) {
158 $this->_error(self::MSG_NUMERIC);
162 if ($value < $this->minimum) {
163 $this->_error(self::MSG_MINIMUM);
167 if ($value > $this->maximum) {
168 $this->_error(self::MSG_MAXIMUM);
177 Открытые свойства <varname>$minimum</varname> и <varname>$maximum</varname>
178 были созданы для установки нижней и верхней границ диапазона
180 В классе также определены две переменные сообщений, которые
181 соответствуют этим открытым свойствам и позволяют использовать
182 <code>min</code> и <code>max</code>
183 в качестве магических параметров в шаблонах сообщений, так же,
184 как и <code>value</code>.
188 Обратите вмимание, что если какая-либо из проверок в методе
189 <code>isValid()</code> не была пройдена, то подготавливается
190 соответствующее сообщение и метод сразу же возвращает
191 <constant>FALSE</constant>.
192 Таким образом, эти правила валидации являются
193 последовательно-зависимыми. Это значит, что если одна из проверок не
194 была пройден, то нет необходимости производить последующие проверки.
195 Но это не обязательный случай, в следующем примере показан
196 класс с независимыми правилами валидации, где объект
197 валидации может возвращать несколько причин, по которым валидация
203 <example id="zend.validate.writing_validators.example.conditions.independent">
205 <title>Валидация с независимыми условиями и возвратом нескольких причин непрохождения валидации</title>
208 Рассмотрим написание класса валидации для обеспечения стойкости
209 пароля, где от пользователя требуется
210 выбрать пароль, который соответствует определенным критериям в целях
211 защиты пользовательского аккаунта.
212 Предположим, что критерии безопасности требуют, чтобы пароль:
216 <para>был длиной как минимум 8 символов,</para>
219 <para>содержал как минимум одну букву в верхнем регистре,</para>
222 <para>содержал как минимум одну букву в нижнем регистре,</para>
225 <para>содержал как минимум один цифровой символ.</para>
231 Следующий класс реализует эти критерии валидации:
233 <programlisting language="php"><![CDATA[
234 class MyValid_PasswordStrength extends Zend_Validate_Abstract
236 const LENGTH = 'length';
237 const UPPER = 'upper';
238 const LOWER = 'lower';
239 const DIGIT = 'digit';
241 protected $_messageTemplates = array(
242 self::LENGTH => "'%value%' должен быть длиной как минимум 8 символов",
243 self::UPPER => "'%value%' должен содержать как минимум одну букву в верхнем регистре",
244 self::LOWER => "'%value%' должен содержать как минимум одну букву в нижнем регистре",
245 self::DIGIT => "'%value%' должен содержать как минимум один цифровой символ"
248 public function isValid($value)
250 $this->_setValue($value);
254 if (strlen($value) < 8) {
255 $this->_error(self::LENGTH);
259 if (!preg_match('/[A-Z]/', $value)) {
260 $this->_error(self::UPPER);
264 if (!preg_match('/[a-z]/', $value)) {
265 $this->_error(self::LOWER);
269 if (!preg_match('/\d/', $value)) {
270 $this->_error(self::DIGIT);
279 Обратите внимание, что эти четыре проверки в методе
280 <code>isValid()</code> не сразу же возвращают <constant>FALSE</constant>.
281 Это позволяет классу валидации предоставлять
282 <emphasis>все</emphasis> причины того, почему
283 введенный пароль не отвечает требованиям валидации.
284 Если, например, пользователь введет строку "<code>#$%</code>"
285 в качестве пароля, то после <code>isValid()</code>
286 вызов <code>getMessages()</code> вернет все четыре
287 сообщения ошибки валидации.