Phalcon\Validation - независимый компонент проверки, который проверяет произвольный набор данных. Этот компонент может использоваться для реализации правил проверки на объектах данных, которые не относятся к модели или коллекции.

В следующем примере показано его основное использование:

<?php

use Phalcon\Validation;
use Phalcon\Validation\Validator\Email;
use Phalcon\Validation\Validator\PresenceOf;

$validation = new Validation();

$validation->add(
    'name',
    new PresenceOf(
        [
            'message' => 'Имя обязательное',
        ]
    )
);

$validation->add(
    'email',
    new PresenceOf(
        [
            'message' => 'Требуется электронная почта',
        ]
    )
);

$validation->add(
    'email',
    new Email(
        [
            'message' => 'Недействительный e-mail',
        ]
    )
);

$messages = $validation->validate($_POST);

if (count($messages)) {
    foreach ($messages as $message) {
        echo $message, '<br>';
    }
}

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

Инициализация проверки

Цепи проверки можно инициализировать напрямую, просто добавив валидаторы в объект Phalcon\Validation. Вы можете поместить свои проверки в отдельный файл для лучшего повторного использования кода и организации:

<?php

use Phalcon\Validation;
use Phalcon\Validation\Validator\Email;
use Phalcon\Validation\Validator\PresenceOf;

class MyValidation extends Validation
{
    public function initialize()
    {
        $this->add(
            'name',
            new PresenceOf(
                [
                    'message' => 'Имя обязательное',
                ]
            )
        );

        $this->add(
            'email',
            new PresenceOf(
                [
                    'message' => 'Требуется электронная почта',
                ]
            )
        );

        $this->add(
            'email',
            new Email(
                [
                    'message' => 'Недействительный e-mail',
                ]
            )
        );
    }
}

Затем инициализируйте и используйте свой собственный валидатор:

<?php

$validation = new MyValidation();

$messages = $validation->validate($_POST);

if (count($messages)) {
    foreach ($messages as $message) {
        echo $message, '<br>';
    }
}

Validators

Phalcon предоставляет набор встроенных валидаторов для этого компонента:

ClassExplanation
Phalcon\Validation\Validator\Alnum Проверяет, что значение поля является только буквенно-цифровым символом.
Phalcon\Validation\Validator\Alpha Проверяет, что значение поля является только буквенным символом.
Phalcon\Validation\Validator\Date Проверяет, что значение поля является допустимой датой.
Phalcon\Validation\Validator\Digit Проверяет, что значение поля - это только числовой символ.
Phalcon\Validation\Validator\File Проверяет, что значение поля является правильным файлом.
Phalcon\Validation\Validator\Uniqueness Проверяет, что значение поля уникально в соответствующей модели.
Phalcon\Validation\Validator\Numericality Проверяет, что значение поля является допустимым числовым значением.
Phalcon\Validation\Validator\PresenceOf Проверяет, что значение поля не является пустой или пустой строкой.
Phalcon\Validation\Validator\Identical Проверяет, что значение поля совпадает с заданным значением.
Phalcon\Validation\Validator\Email Проверяет, что это поле содержит допустимый формат электронной почты.
Phalcon\Validation\Validator\ExclusionIn Проверяет, что значение не входит в список возможных значений.
Phalcon\Validation\Validator\InclusionIn Проверяет, что значение находится в списке возможных значений.
Phalcon\Validation\Validator\Regex Проверяет, что значение поля соответствует регулярному выражению.
Phalcon\Validation\Validator\StringLength Проверяет длину строки.
Phalcon\Validation\Validator\Between Проверяет, что значение находится между двумя значениями.
Phalcon\Validation\Validator\Confirmation Проверяет, что значение совпадает с другим, присутствующим в данных.
Phalcon\Validation\Validator\Url Проверяет, что это поле содержит допустимый URL.
Phalcon\Validation\Validator\CreditCard Проверяет номер кредитной карты.
Phalcon\Validation\Validator\Callback Проверяет использование функции обратного вызова.

В следующем примере объясняется, как создать дополнительные валидаторы для этого компонента:

<?php

use Phalcon\Validation;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator;

class IpValidator extends Validator
{
    /**
     * Выполняет проверку
     *
     * @param Validation $validator
     * @param string     $attribute
     * @return boolean
     */
    public function validate(Validation $validator, $attribute)
    {
        $value = $validator->getValue($attribute);

        if (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
            $message = $this->getOption('message');

            if (!$message) {
                $message = 'IP недействителен';
            }

            $validator->appendMessage(
                new Message($message, $attribute, 'Ip')
            );

            return false;
        }

        return true;
    }
}

Важно, чтобы валидаторы возвращали действительное логическое значение, указывающее, была ли проверка успешной или нет.

Валидатор обратного вызова

Используя Phalcon\Validation\Validator\Callback , вы можете выполнить пользовательскую функцию, которая должна возвращать boolean или новый класс проверки, который будет использоваться для проверки того же поля. Возвращая true валидаця - успешна, возврат false означает, что проверка не прошла. При выполнении этого валидатора Phalcon передает данные в зависимости от того, что это такое - если это сущность, то объект будет передан, иначе данные. Пример:

<?php

use \Phalcon\Validation;
use \Phalcon\Validation\Validator\Callback;
use \Phalcon\Validation\Validator\PresenceOf;

$validation = new Validation();
$validation->add(
    'amount',
    new Callback(
        [
            'callback' => function($data) {
                return $data['amount'] % 2 == 0;
            },
            'message'  => 'Принимается только четное количество продуктов'
        ]
    )
);
$validation->add(
    'amount',
    new Callback(
        [
            'callback' => function($data) {
                if($data['amount'] % 2 == 0) {
                    return $data['amount'] != 2;
                }

                return true;
            },
            'message' => "Вы не можете купить 2 продукта"
        ]
    )
);
$validation->add(
    'description',
    new Callback(
        [
            'callback' => function($data) {
                if($data['amount'] >= 10) {
                    return new PresenceOf(
                        [
                            'message' => 'Вы должны написать, почему вам нужна такая большая сумма.'
                        ]
                    );
                }

                return true;
            }
        ]
    )
);

// будет возвращать сообщение с первого валидатора
$messages = $validation->validate(['amount' => 1]); 

// будет возвращать сообщение от второго валидатора 
$messages = $validation->validate(['amount' => 2]);

// будет возвращать сообщение из валидатора, возвращаемого третьим валидатором 
$messages = $validation->validate(['amount' => 10]); 

Сообщения о проверке

Phalcon\Validation имеет подсистему обмена сообщениями, которая обеспечивает гибкий способ вывода или хранения сообщений проверки, сгенерированных во время процессов проверки.

Каждое сообщение состоит из экземпляра класса Phalcon\Validation\Message. Набор генерируемых сообщений можно получить с помощью метода getMessages(). Каждое сообщение предоставляет расширенную информацию, такую ​​как атрибут, который сгенерировал сообщение или тип сообщения:

<?php

$messages = $validation->validate();

if (count($messages)) {
    foreach ($messages as $message) {
        echo 'Message: ', $message->getMessage(), "\n";
        echo 'Field: ', $message->getField(), "\n";
        echo 'Type: ', $message->getType(), "\n";
    }
}

Вы можете передать параметр message для изменения / перевода сообщения по умолчанию в каждом валидаторе, даже если вы можете использовать подстановочный знак: :field в сообщении, которое должно быть заменено меткой поля:

<?php

use Phalcon\Validation\Validator\Email;

$validation->add(
    'email',
    new Email(
        [
            'message' => 'Недействительный e-mail',
        ]
    )
);

По умолчанию метод getMessages() возвращает все сообщения, созданные во время проверки. Вы можете фильтровать сообщения для определенного поля с помощью метода filter():

<?php

$messages = $validation->validate();

if (count($messages)) {
    // Отфильтровать только сообщения, сгенерированные для поля 'name'
    $filteredMessages = $messages->filter('name');

    foreach ($filteredMessages as $message) {
        echo $message;
    }
}

Фильтрация данных

Данные могут быть отфильтрованы до проверки, гарантируя, что вредоносные или неверные данные не будут проверены.

<?php

use Phalcon\Validation;

$validation = new Validation();

$validation->add(
    'name',
    new PresenceOf(
        [
            'message' => 'Имя обязательное',
        ]
    )
);

$validation->add(
    'email',
    new PresenceOf(
        [
            'message' => 'Требуется электронная почта',
        ]
    )
);

// Filter any extra space
$validation->setFilters('name', 'trim');
$validation->setFilters('email', 'trim');

Фильтрация и дезинфекция выполняются с использованием компонента фильтра. Вы можете добавить дополнительные фильтры к этому компоненту или использовать встроенные.

События проверки

Когда проверки проводятся в классах, вы можете реализовать методы beforeValidation() и afterValidation() для выполнения дополнительных проверок, фильтров, очистки и т. Д. Если метод beforeValidation() возвращает false, проверка автоматически отменяется:

<?php

use Phalcon\Validation;

class LoginValidation extends Validation
{
    public function initialize()
    {
        // ...
    }

    /**
     * Выполнено до проверки
     *
     * @param array $data
     * @param object $entity
     * @param Phalcon\Validation\Message\Group $messages
     * @return bool
     */
    public function beforeValidation($data, $entity, $messages)
    {
        if ($this->request->getHttpHost() !== 'admin.mydomain.com') {
            $messages->appendMessage(
                new Message('Только пользователи могут войти в домен администрирования')
            );

            return false;
        }

        return true;
    }

    /**
     * Выполнено после проверки
     *
     * @param array $data
     * @param object $entity
     * @param Phalcon\Validation\Message\Group $messages
     */
    public function afterValidation($data, $entity, $messages)
    {
        // ... Добавление дополнительных сообщений или выполнение дополнительных проверок
    }
}

Отмена проверки

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

<?php

use Phalcon\Validation;
use Phalcon\Validation\Validator\Regex;
use Phalcon\Validation\Validator\PresenceOf;

$validation = new Validation();

$validation->add(
    'telephone',
    new PresenceOf(
        [
            'message'      => 'Требуется телефон',
            'cancelOnFail' => true,
        ]
    )
);

$validation->add(
    'telephone',
    new Regex(
        [
            'message' => 'Требуется телефон',
            'pattern' => '/\+44 [0-9]+/',
        ]
    )
);

$validation->add(
    'telephone',
    new StringLength(
        [
            'messageMinimum' => 'Телефон слишком короткий',
            'min'            => 2,
        ]
    )
);

В первом валидаторе есть опция cancelOnFail со значением true, поэтому, если этот валидатор не работает, остальные валидаторы в цепочке не выполняются.

Если вы создаете настраиваемые валидаторы, вы можете динамически остановить цепочку валидации, установив параметр cancelOnFail:

<?php

use Phalcon\Validation;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator;

class MyValidator extends Validator
{
    /**
     * Выполняет проверку
     *
     * @param Phalcon\Validation $validator
     * @param string $attribute
     * @return boolean
     */
    public function validate(Validation $validator, $attribute)
    {
        // Если значение атрибута является именем, мы должны остановить цепочку
        if ($attribute === 'name') {
            $validator->setOption('cancelOnFail', true);
        }

        // ...
    }
}

Избегайте проверки пустых значений

Вы можете передать параметр allowEmpty всем встроенным валидаторам, чтобы избежать проверки правильности при пустом значении:

<?php

use Phalcon\Validation;
use Phalcon\Validation\Validator\Regex;

$validation = new Validation();

$validation->add(
    'telephone',
    new Regex(
        [
            'message'    => 'Требуется телефон',
            'pattern'    => '/\+44 [0-9]+/',
            'allowEmpty' => true,
        ]
    )
);

Рекурсивная проверка

Вы также можете запускать экземпляры проверки в другом через метод afterValidation(). В этом примере проверка экземпляра CompanyValidation также проверяет экземпляр PhoneValidation:

<?php

use Phalcon\Validation;

class CompanyValidation extends Validation
{
    /**
     * @var PhoneValidation
     */
    protected $phoneValidation;

    public function initialize()
    {
        $this->phoneValidation = new PhoneValidation();
    }

    public function afterValidation($data, $entity, $messages)
    {
        $phoneValidationMessages = $this->phoneValidation->validate(
            $data['phone']
        );

        $messages->appendMessages(
            $phoneValidationMessages
        );
    }
}