Добавляем правила проверки данных на лету

Все в общем-то, тривиально и не стоило бы, наверное, пост городить. Но рассматривая код некоторых проектов на 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.

  1. Данные из поля формы User.email должны быть идентичны данным из поля формы User.confirm_email
  2. Данные из поля формы User.password должны быть идентичны данным из поля формы User.confirm_password
  3. Данные из поля формы User.captcha должны быть идентичны содержимому переменной сессии Captcha.code
  4. Поле 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() или типа того. Получится стильно и благородно. ;-)

Related Posts with Thumbnails
07.02.2009 • Метки: , , , , • Рубрики: CakePHP
blog comments powered by Disqus