Добавляем правила проверки данных на лету
Все в общем-то, тривиально и не стоило бы, наверное, пост городить. Но рассматривая код некоторых проектов на CakePHP я обнаружил удивительную вещь — во многих случаях данные формы проверяются не встроенным валидатором, а специально написанным кодом. Зачем? Непонятно.
Во-первых правила проверки — это просто ассоциативный массив, в который вполне можно добавлять элементы, прямо из метода контроллера. Никуда они при инициализации модели, не парсятся и не обрабатываются, пока не будет вызван валидатор.
Во-вторых валидатор отлично справляется с полями формы, которым нет соответствия в модели. А метод модели save() записывает только те поля, которым соответствуют колонки в таблице.
Вот, например, простая форма регистрации пользователя.
Форма очень человеколюбивая, и, даже, не побоюсь этого выражения, user-friendly: у нее есть 2 поля с E-mail (второе для проверки), 2 поля с паролем и еще капча. Регистрируйтесь, наздоровье. :-)
В модели User, само собой, есть только колонки ‘email’ и ‘password’, без дубликатов, а колонка ‘captcha’ отсутствует совсем.
Изначально в классе модели правила проверки полей ‘email’ и ‘password’ определены вот такие:
var $validate = array( /**************** Password **************/ 'password' => array( 'minlength' => array( 'rule' => array('minLength', '6'), 'message' => 'Password must be at least 6 characters long.', 'allowEmpty' => false, 'required' => true, 'last' => true ), ), /************* E-mail ************************/ 'email' => array( 'mailrule' => array( 'rule' => array('email', true), 'message' => 'Please supply a valid email address.', 'allowEmpty' => false, 'required' => true, 'last' => true ), /* This field mus be unique */ 'must_be_unique' => array( 'rule' => 'isUnique', 'message' => 'User with this e-mail address is already registered', 'last' => true ) ) );
Правил для поля captcha, не определено никаких.
В шаблоне вида, форма и поля выводятся с помощью встроенного помощника (helper) Form. Примерно вот так:
echo $form->create('User', array('action'=>'register')); /* ввод username и прочего пропущены */ echo $form->input('User.email'); echo $form->input('User.confirm_email'); echo $form->input('User.password'); echo $form->input('User.confirm_password', array('type' => 'password')); echo $form->input('User.captcha', array( 'label'=>'Что там на картинке?', 'type'=>'text', 'value'=>'')); echo $form->end(__('Пыщь!!111', true));
А в методе, который отвечает за запись данных, я, перед вызовом User->save(), просто добавляю еще дополнительные правила для email, password и captcha.
- Данные из поля формы User.email должны быть идентичны данным из поля формы User.confirm_email
- Данные из поля формы User.password должны быть идентичны данным из поля формы User.confirm_password
- Данные из поля формы User.captcha должны быть идентичны содержимому переменной сессии Captcha.code
- Поле User.captcha не может быть пустым
/* Чтоб сравнивать пароли понадобится помощь * компонента авторизации */ $this->User->validate['password']['confirm'] = array( 'rule'=>array( 'equalTo', ( isset($this->data['Confirm']['password']) ? $this->Auth->password($this->data['Confirm']['password']) : '') ), 'message'=>'Пароли не одинаковые' ); $this->User->validate['email']['confirm'] = array( 'rule'=>array('equalTo', ( isset($this->data['Confirm']['email']) ? $this->data['Confirm']['email'] : '')), 'message'=>'E-mail адреса не одинаковые' ); /* Получаем код капчи из сессии, а если его нет, сравнивать * будем с пустой строкой */ $captcha_code = $this->Session->check('Captcha.code') ? $this->Session->read('Captcha.code') : ''; $this->Session->del('Captcha.code'); /* Дбавляем единственное правило для несуществующего поля */ $this->User->validate['captcha'] = array( 'rule' => array('equalTo', $captcha_code), 'required' => true, 'allowEmpty' => false, 'message' => "You're a spam bot?" ); /* ну и здесь */ if ($this->User->save($this->data)) // и так далее
Конечно, строчек кода, если и меньше, чем просто в случае сравнения, то ненамного. Зато встроенный валидатор отлично взаимодействует со встроенным помощником (helper) Form — сообщения об ошибках записываются в переменную validationErrors, выводятся «автомагически» рядом с соответствующими полями формы и т.д.
И уж совсем необязательно все это выписывать именно в контроллере перед вызовом save(). Можно добавить методов модели типа addCaptchaRule(), addEmailConfirmationRule() или типа того. Получится стильно и благородно. ;-)



