Содержание


Создание валидаторов


Writing Validators, Валидация, ЗФ2, Zend Framework 2, ZF2, ру, ru



 

Zend\Validator предоставляет набор наиболее востребованных валидаторов, но неизбежна ситуация, когда разработчикам понадобиться написать собственные валидаторы для конкретных нужд. Задача создания собственных валидаторов описана в этом разделе.

 

В Zend\Validator\ValidatorInterface определены два метода, isValid() и getMessages(), которые должны быть реализованы пользовательскими классами для создания собственных объектов валидации. Объект, который реализует интерфейс Zend\Validator\AbstractValidator, может быть добавлен в цепочку валидаторов с помощью Zend\Validator\ValidatorChain::addValidator(). Такие объекты могут быть также использованы с Zend\Filter\Input.

 

Как вы уже поняли из приведенного выше описания Zend\Validator\ValidatorInterface, классы валидации, которые предоставляет Zend Framework, возвращают логическое значение того, успешна или нет проверка некоторого значения. Они также предоставляют информацию о том, почему значение не прошло проверку. Наличие причин провала валидации может быть полезно в приложении для различных целей, таких, как предоставление статистики для удобства анализа.

 

Базовая функциональность сообщений об ошибках валидации реализована в Zend\Validator\AbstractValidator. Чтобы включить эту функциональность при создании класса валидации, просто наследуйте Zend\Validator\AbstractValidator. В дочернем классе вы можете реализовать логику метода isValid() и определить переменные сообщений и шаблоны сообщений, соответствующие типам ошибок валидации, которые могут возникнуть. Если значение не проходит проверку, то isValid() должен возвращать FALSE. Если значение проходит проверку, то isValid() должен возвращать TRUE.

 

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

 



Создание простого класса валидации

 

Следующий пример демонстрирует создание простейшего валидатора. В этом случае правила валидации просто состоят в том, что входное значение должно быть числом с плавающей запятой.

class MyValid\Float extends Zend\Validator\AbstractValidator
{
    const FLOAT = 'float';
 
    protected $messageTemplates = array(
        self::FLOAT => "'%value%' is not a floating point value"
    );
 
    public function isValid($value)
    {
        $this->setValue($value);
 
        if (!is_float($value)) {
            $this->error(self::FLOAT);
            return false;
        }
 
        return true;
    }
}
 

Класс определяет шаблон для единственного сообщения об ошибке валидации, который включает встроенный магический параметр, %value%. Вызов setValue() автоматически подготавливает объект для вставки проверяемого значения в сообщение об ошибке, если это значение не пройдет проверку. Вызов error() устанавливает причину сбоя проверки. Так как в этом классе определено только одно сообщение об ошибке, то не нужно передавать в error() имя шаблона сообщения об ошибке.

 

 

Создание классов валидации, имеющих подчиненные условия (исполнение которого не может быть потребовано до исполнения другого, предварительного условия)

 

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

• входное значение не является числом.

• входное значение меньше минимально допустимого значения.

• входное значение больше максимально допустимого значения.

 

Эти причины ошибок валидации преобразованы в константы класса:

class MyValid\NumericBetween extends Zend\Validator\AbstractValidator
{
    const MSG_NUMERIC = 'msgNumeric';
    const MSG_MINIMUM = 'msgMinimum';
    const MSG_MAXIMUM = 'msgMaximum';
 
    public $minimum = 0;
    public $maximum = 100;
 
    protected $messageVariables = array(
        'min' => 'minimum',
        'max' => 'maximum'
    );
 
    protected $messageTemplates = array(
        self::MSG_NUMERIC => "'%value%' is not numeric",
        self::MSG_MINIMUM => "'%value%' must be at least '%min%'",
        self::MSG_MAXIMUM => "'%value%' must be no more than '%max%'"
    );
 
    public function isValid($value)
    {
        $this->setValue($value);
 
        if (!is_numeric($value)) {
            $this->error(self::MSG_NUMERIC);
            return false;
        }
 
        if ($value < $this->minimum) {
            $this->error(self::MSG_MINIMUM);
            return false;
        }
 
        if ($value > $this->maximum) {
            $this->error(self::MSG_MAXIMUM);
            return false;
        }
 
        return true;
    }
}
 

Публичные свойства $minimum и $maximum были созданы, чтобы обеспечить минимальный и максимальный пороги, для которых значение успешно проходит валидацию. В классе также определены две переменные сообщений, которые соответствуют публичным свойствам и позволяют использовать min и max в шаблонах сообщений в качестве магических параметров, как и value.

 

Заметим, что если любая из проверок в методе isValid() будет провалена, это подготовит соответствующее сообщение об ошибке, и метод немедленно вернет FALSE. Поэтому такие правила валидации являются последовательно-зависимыми. То есть, если одна из проверок будет провалена, нет необходимости производить последующие проверки. Однако, это не обязательно. Следующий пример иллюстрирует, как создать класс с независимыми правилами проверки, чей объект валидации может возвращать несколько причин, по которым конкретная валидация не удалась.

 

Создание классов валидации с взаимно не связанными условиями и множеством допустимых причин для сбоя

 

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

• минимум 8 символов,

• содержать хотя бы одну букву в верхнем регистре,

• содержать хотя бы одну букву в нижнем регистре,

• содержать хотя бы одну цифру.

 

Следующий класс реализует эти критерии проверки:

class MyValid\PasswordStrength extends Zend\Validator\AbstractValidator
{
    const LENGTH = 'length';
    const UPPER  = 'upper';
    const LOWER  = 'lower';
    const DIGIT  = 'digit';
 
    protected $messageTemplates = array(
        self::LENGTH => "'%value%' must be at least 8 characters in length",
        self::UPPER  => "'%value%' must contain at least one uppercase letter",
        self::LOWER  => "'%value%' must contain at least one lowercase letter",
        self::DIGIT  => "'%value%' must contain at least one digit character"
    );
 
    public function isValid($value)
    {
        $this->setValue($value);
 
        $isValid = true;
 
        if (strlen($value) < 8) {
            $this->error(self::LENGTH);
            $isValid = false;
        }
 
        if (!preg_match('/[A-Z]/', $value)) {
            $this->error(self::UPPER);
            $isValid = false;
        }
 
        if (!preg_match('/[a-z]/', $value)) {
            $this->error(self::LOWER);
            $isValid = false;
        }
 
        if (!preg_match('/\d/', $value)) {
            $this->error(self::DIGIT);
            $isValid = false;
        }
 
        return $isValid;
    }
}
 

Заметьте, что эти четыре проверки в методе isValid() не возвращают немедленно FALSE. Это позволяет классу валидации предоставить все причины того, почему введенный пароль не отвечает требованиям валидации. Например, если пользователь введет строку “#$%” в качестве пароля, isValid() будет обуславливать все четыре сообщения об ошибке валидации, чтобы вернуть их последующим вызовом getMessages().