Создание своего правила валидации (validation rule) / Yii framework


Оригинал: Create your own Validation Rule

Иногда, стандартные правила валидации фреймворка Yii, могут не удовлетворять треованиям системы. В этом случае необходим создать свое правило валидации.

Быстрый способ

Самый простой способ создать новое правило проверки, это написание специального метода внутри модели, в которой он будет использоваться.

Предположим, что мы хотим проверить, является ли пароль пользователя достаточно безопасным.
Как правило, мы могли бы проверить пароль с помощью CRegularExpressionValidator, но давайте представим, что такого валидатор не существует.

Прежде всего в вашем классе модели вам придется добавить две константы:
const WEAK = 0;
const STRONG = 1;


Затем необходимо описать метод, который будет использоваться в качестве валидатора:
/**
 * Метод проверяет силу пароля
 * Этот метод является валидатором 'passwordStrength' для метода rules().
 */
public function passwordStrength($attribute,$params)
{
    if ($params['strength'] === self::WEAK)
        $pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';  
    elseif ($params['strength'] === self::STRONG)
        $pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';  
 
    if(!preg_match($pattern, $this->$attribute))
      $this->addError($attribute, 'пароль слишком слабый');
}

Убедитесь, что Вы используете уникальное имя метода, в противном случае возможны конфликты в системе.

Новый метод принимает два параметра:
  • $attribute — название атрибута, который валидируется в данный момент
  • $params — дополнительные параметры, объявленные в списке парвил валидации (в данном примере array('strength'=>self::STRONG))

Далее, все что остается, это добавить новый валидат в список правил проверки:
public function rules()
{
    return array(
		...
		array('password', 'passwordStrength', 'strength'=>self::STRONG),
		...
	);
}

Как Вы могли заметить, внутри метода passwordStrength мы делаем вызов CModel::addError.
Данный метод регистрирует ошибку валидации. Принимает два параметра:
  • $attribute — имя атрибута, к которому относится ошибка
  • $error — сообщение об ошибке

Менее быстрый способ

Если Вы планируете использовать новое правило валидации более чем в одной модели, то лучше создавать правило через расширение класса CValidator.
Этот способ имеет ещё несколько преимуществ. Например мы сможем использовать параметр CActiveForm::$enableClientValidation из виджета формы.

Создание класса
Первое, что нам нужно сделать, это создать файл класса. Давайте создадим новую папку MyValidators внутри расширений приложения (директория protected/extensions). И создадим в новой директории файл passwordStrength.php

Внутри этого файла описываем класс валидации:
class passwordStrength extends CValidator{
	const WEAK = 0;
	const STRONG = 1;

    public $strength;
 
    private $weak_pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';
    private $strong_pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';
...

В теле класса необходимо создать атрибуты для каждого дополнительного параметра, который Вы хотите использовать в Ваших правилах проверки.
Мы также создали два других атрибута, каждый из которых содержит паттерны, которые мы хотим использовать в нашей функции проверки (preg_match).

Теперь мы должны описать метод ValidateAttribute
/**
 * Метод проверяет силу пароля
 * @param CModel $object модель валидации
 * @param string $attribute атрибут, который валидируется в данный момент
 */
protected function validateAttribute($object,$attribute){
    // проверяем параметр strength и выбираем паттерн для preg_match
    if ($this->strength == self::WEAK)
      $pattern = $this->weak_pattern;
    elseif ($this->strength == self::STRONG)
      $pattern = $this->strong_pattern;
 
    // получаем значение атрибуа модели и проверяем по паттерну
    $value=$object->$attribute;
    if(!preg_match($pattern, $value)){
        $this->addError($object,$attribute,'Ваш пароль слишком слабый.');
    }
}


Реализация проверки на клиенте (javascript)
Если вы хотите осуществлять проверку в браузере, Вам нужно переопределить один метод в вашем классе: clientValidateAttribute
/**
 * Метод возвращает javascript для валидации на клиенте
 * @param CModel $object модель
 * @param string $attribute имя атрибута валидации
 * @return string javascript
 * @see CActiveForm::enableClientValidation
 */
public function clientValidateAttribute($object,$attribute){
    // проверяем параметр strength и выбираем паттерн
    if ($this->strength == self::WEAK)
      $pattern = $this->weak_pattern;
    elseif ($this->strength == self::STRONG)
      $pattern = $this->strong_pattern;     
 
    $condition="!value.match({$pattern})";
 
    return "
if(".$condition.") {
    messages.push(".CJSON::encode('Ваш пароль слишком слабый.').");
}
";
}

Как Вы могли заметит, этот метод просто возвращает javascript код, который будет использован для проверки.

Последний шаг: как использовать новый класс валидации
Для начала в файле модели необходимо подключить новый валидатор через Yii::import, азатем объявить массив правил проверки:
public function rules(){
	Yii::import('ext.MyValidators.passwordStrength');
	return array(
		...
		array('password', 'passwordStrength', 'strength'=>passwordStrength::STRONG),
		...
	);
}


Вот и все. Собственное правило валидации успешно создано. Приятного кодинга.