Очень удобная вещь - Zend_Form. Данный компонент предоставляет множество возможностей, таких как фильтрация и валидация данных формы. Zend_Form имеет ряд собственных валидаторов и фильтров, но он достаточно гибок, и есть возможность создавать свои классы для валидации.
Рассмотрим на примере создание собственного валидатора для формы регистрации.
Возьмем простейшую форму для регистрации, с минимальным набором полей:
- логин
- пароль
- пароль повторно
Требования к полям:
- Логин - обязательное поле, строка из цифро-буквенных символов длиною от 3 до 15 символов, уникальное.
- email - обязательное поле, имеет правильный формат, уникальное.
- Пароль - обязательное поле, строка из любых символов, не короче 6 символов
- Пароль повторно - поле должно совпадать с полем ‘пароль’.
Исходя их требований, можно сделать вывод, что нам нужно написать 3 собственных валидатора:
- Проверка уникальности логина.
- Проверка уникальности email.
- Проверка совпадения паролей.
Для создания custom validator, нужно наследовать класс от абстрактного Zend_Validate_Abstract, и реализовать в нем метод isValid.
В своих проектах валидаторы я храню в директории models/validator.
Создание валидатора уникальности логина
Создаем новый файл models/validator/UniqueNickname.php
<?php class Validator_UniqueNickname extends Zend_Validate_Abstract { const NOT_UNIQUE = ‘notUnique’; /* * Сообщения об ошибках валидации */ protected $_messageTemplates = array( self::NOT_UNIQUE => “Username ‘%value%’ has already been taken” ); public function isValid($value) { $this->_setValue($value); $isValid = true; /* * Метод User::checkLogin проверяет используется ли в базе такой логин, * если да, то возвращает user id */ $userId = User::checkLogin($value); if ($userId) { $this->_error(self::NOT_UNIQUE); $isValid = false; } return $isValid; } }
Создание валидатора уникальности email
Создаем новый файл models/validator/UniqueEmail.php
<?php class Validator_UniqueEmail extends Zend_Validate_Abstract { const NOT_UNIQUE = ‘notUnique’; protected $_messageTemplates = array( self::NOT_UNIQUE => “Email ‘%value%’ has already been taken” ); public function isValid($value) { $this->_setValue($value); $isValid = true; $userId = User::checkEmail($value); if ($userId) { $this->_error(self::NOT_UNIQUE); $isValid = false; } return $isValid; } }
Создание валидатора для паролей
С этим валидатором дела обстоят интереснее. Создаем новый файл models/validator/EqualValues.php.
<?php class Validator_EqualValues extends Zend_Validate_Abstract { const NOT_EQUAL = ‘notEqual’; protected $_messageTemplates = array( self::NOT_EQUAL => ‘Passwords are not equal’ ); protected $_contextKey; public function __construct($key) { $this->_contextKey = $key; } public function isValid($value, $context = null) { if (is_array($context)) { if (isset($context[$this->_contextKey]) && ($value === $context[$this->_contextKey])) { return true; } } if ($value === $context) { return true; } $this->_error(self::NOT_EQUAL); return false; } }
Форма регистрации
Теперь создаем непосредственно саму форму регистрации (models/form/Register.php)
<?php class Form_Register extends Zend_Form { public function __construct($options = null) { parent::__construct($options); $this->setAction(HOME_URL . ‘register/’) ->setMethod(‘post’); $login = new Zend_Form_Element_Text(‘login’); $login->setLabel(‘Логин’) ->setRequired(true) ->addFilter(‘StripTags’) ->addFilter(‘StringTrim’) ->addFilter(‘StringToLower’) ->addValidator(‘StringLength’, true, array(‘min’ => 3, ‘max’ => 15)) ->addValidator(‘alnum’) ->addValidator(new Validator_UniqueNickname()) ; $email = new Zend_Form_Element_Text(‘email’); $email->setLabel(‘email’) ->setRequired(true) ->addFilter(‘StripTags’) ->addFilter(‘StringTrim’) ->addFilter(‘StringToLower’) ->addValidator(new Zend_Validate_EmailAddress()) ->addValidator(new Validator_UniqueEmail()) ; $password = new Zend_Form_Element_Password(‘password’); $password->setLabel(‘Пароль’) ->setRequired(true) ->addValidator(‘StringLength’, true, array(‘min’ => 6)) ; $passwordAgain = new Zend_Form_Element_Password(‘passwordAgain’); $passwordAgain->setLabel(‘Повторите пароль’); // Валидатор для совпадения паролей $passwordAgain->addValidator(new Validator_EqualValues(‘password’)) ->setAllowEmpty(false); $submit = new Zend_Form_Element_Submit(’submit’); $submit->setLabel(‘Ok’); $this->addElements(array($login, $email, $password, $passwordAgain, $submit)); } }
При добавлении валидатора для паролей нужно вызывать метод setAllowEmpty со значением false. Это делается для того чтобы валидатор паролей срабатывал при пустом значении “Пароль повторно”.
Сам процесс регистрации не входит в рамки данной статьи, возможно позже напишу продолжение данной статьи.
Апрель 15th, 2009 at 3:13 пп
А зачем у вас проверка
if (is_string($context) && ($value === $context)) {
? ^_^
Что будет если не строка?
Апрель 15th, 2009 at 3:17 пп
:)
Эта часть была скопирована с примера, который приводил san.
Но, во всяком случае $context будет строкой, так что проверку is_string можно убрать.
Спасибо за замечание.
Апрель 15th, 2009 at 3:54 пп
Вместо того что бы писать для каждого поля свой валидатор на уникальность, я использую универсальный http://zendframework.ru/articles/zend-validate-examples#nodbexists
Апрель 15th, 2009 at 4:59 пп
Согласен, а то получилось дублирование кода.
Спасибо за совет.
Апрель 16th, 2009 at 10:04 пп
Зендом увлекся? А я вот на симфони)) похоливарим?
Апрель 17th, 2009 at 8:38 дп
Не то слово увлекся!
С утра до вечера - один Zend Framework :)
Холиварить нет смысла, т.к. symfony я тоже люблю!
Апрель 25th, 2009 at 9:03 дп
Очень интересно, почему валидатор лежит именно в models/validator/ а не где - то ещё. Это продиктовано вкусовыми пристрастиями или суровой необходимостью?
Интересно также почему форма лежит в models/form. В зендовском туториале формы кладут в application/form вроде.
Апрель 26th, 2009 at 12:20 пп
Вот черт, формы через php объекты действительно рулят, надо и мне переучить себя ). Ко всему вышенаписанному хочу добавить, что в самом процессе регистрации я бы не надеялся на метод User::checkLogin() или User::checkEmail(), а ловил бы Exception, который генерится при попытке вставки в таблицу дублированных данных (поля с UNIQUE INDEX)
Апрель 27th, 2009 at 5:15 пп
@terix:
В принципе, разработчик сам в праве выбирать место для своих классов - мне так удобнее.
Апрель 27th, 2009 at 5:24 пп
@[YS.PRO]:
ну на счет Exception: по-моему это слишком… По крайней мере такого еще нигде не встречал.