Spec-Zone.ru › Yii 2.0

Валидация ввода

  1. Определение правил
  2. Валидация ad hoc
  3. Создание валидаторов
  4. Валидация нескольких атрибутов
  5. Валидация на стороне клиента

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

Учитывая модель, заполненную пользовательским вводом, вы можете проверить ввод, вызвав метод yii\base\Model::validate(). Метод вернёт булево значение, указывающее, была ли валидация успешной или нет. Если нет, вы можете получить сообщения об ошибках из свойства yii\base\Model::$errors. Например,

$model = new \app\models\ContactForm();

// populate model attributes with user inputs
$model->load(\Yii::$app->request->post());
// which is equivalent to the following:
// $model->attributes = \Yii::$app->request->post('ContactForm');

if ($model->validate()) {
    // all inputs are valid
} else {
    // validation failed: $errors is an array containing error messages
    $errors = $model->errors;
}

Определение правил

Чтобы validate() действительно сработал, вы должны определить правила валидации для атрибутов, которые вы планируете проверять. Это делается путём переопределения метода yii\base\Model::rules(). Следующий пример показывает, как определяются правила валидации для ContactForm модели:

public function rules()
{
    return [
        // the name, email, subject and body attributes are required
        [['name', 'email', 'subject', 'body'], 'required'],

        // the email attribute should be a valid email address
        ['email', 'email'],
    ];
}

Метод rules() должен возвращать массив правил, каждый из которых является массивом следующего формата:

[
    // required, specifies which attributes should be validated by this rule.
    // For a single attribute, you can use the attribute name directly
    // without having it in an array
    ['attribute1', 'attribute2', ...],

    // required, specifies the type of this rule.
    // It can be a class name, validator alias, or a validation method name
    'validator',

    // optional, specifies in which scenario(s) this rule should be applied
    // if not given, it means the rule applies to all scenarios
    // You may also configure the "except" option if you want to apply the rule
    // to all scenarios except the listed ones
    'on' => ['scenario1', 'scenario2', ...],

    // optional, specifies additional configurations for the validator object
    'property1' => 'value1', 'property2' => 'value2', ...
]

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

  • псевдоним ядра валидатора, например required, in, date, и т. д. Обратитесь к Ядерным валидаторам за полным списком ядровых валидаторов.
  • имя метода валидации в классе модели или анонимная функция. Подробности см. в подразделе Встроенные валидаторы.
  • полное имя класса валидатора. Подробности см. в подразделе Валидаторы, стоящие отдельно.

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

Когда вызывается метод validate(), он выполняет следующие шаги для выполнения валидации:

  1. Определяет, какие атрибуты должны быть проверены, получив список атрибутов из yii\base\Model::scenarios() с использованием текущего сценария. Эти атрибуты называются активными атрибутами.
  2. Определяет, какие правила валидации должны быть использованы, получив список правил из yii\base\Model::rules() с использованием текущего сценария. Эти правила называются активными правилами.
  3. Использует каждое активное правило для проверки каждого активного атрибута, связанного с правилом. Правила валидации оцениваются в том порядке, в котором они перечислены.

Согласно вышеуказанным этапам валидации, атрибут будет проверен только в том случае, если он является активным атрибутом, объявленным в scenarios(), и связан с одним или несколькими активными правилами, объявленными в rules().

Примечание: Удобно давать имена правилам, например

public function rules()
{
    return [
        // ...
        'password' => [['password'], 'string', 'max' => 60],
    ];
}

Вы можете использовать его в дочерней модели:

public function rules()
{
    $rules = parent::rules();
    unset($rules['password']);
    return $rules;
}

Настройка сообщений об ошибках

Большинство валидаторов имеют стандартные сообщения об ошибках, которые будут добавлены в модель, которая проверяется, когда её атрибуты не пройдут проверку. Например, валидатор required добавит сообщение "Имя пользователя не может быть пустым" в модель, когда атрибут username не удовлетворяет правилу, использующему этот валидатор.

Вы можете настроить сообщение об ошибке правила, указав свойство message, при объявлении правила, например:

public function rules()
{
    return [
        ['username', 'required', 'message' => 'Please choose a username.'],
    ];
}

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

События валидации

При вызове yii\base\Model::validate() будут вызваны два метода, которые вы можете переопределить для настройки процесса валидации:

  • yii\base\Model::beforeValidate(): стандартная реализация инициирует событие yii\base\Model::EVENT_BEFORE_VALIDATE. Вы можете переопределить этот метод или ответить на это событие, чтобы выполнить некоторые подготовительные работы (например, нормализацию входных данных) перед проверкой. Метод должен возвращать булево значение, указывающее, нужно ли продолжать валидацию.
  • yii\base\Model::afterValidate(): стандартная реализация инициирует событие yii\base\Model::EVENT_AFTER_VALIDATE. Вы можете переопределить этот метод или ответить на это событие, чтобы выполнить некоторые пост-обрабатывающие работы после завершения проверки.

Условная валидация

Чтобы проверять атрибуты только при выполнении определенных условий, например, когда проверка одного атрибута зависит от значения другого атрибута, вы можете использовать свойство when для определения таких условий. Например,

    ['state', 'required', 'when' => function($model) {
        return $model->country == 'USA';
    }]

Свойство when принимает вызываемый PHP-объект со следующим сигнатурным значением:

/**
 * @param Model $model the model being validated
 * @param string $attribute the attribute being validated
 * @return bool whether the rule should be applied
 */
function ($model, $attribute)

Если вам также нужно поддерживать условную валидацию на стороне клиента, вы должны настроить свойство whenClient, которое принимает строку, представляющую функцию JavaScript, возвращаемое значение которой определяет, нужно ли применять правило или нет. Например,

    ['state', 'required', 'when' => function ($model) {
        return $model->country == 'USA';
    }, 'whenClient' => "function (attribute, value) {
        return $('#country').val() == 'USA';
    }"]

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

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

Следующие примеры показывают, как обрезать пробелы ввода и превращать пустые входы в null, используя ядровые валидаторы trim и default:

return [
    [['username', 'email'], 'trim'],
    [['username', 'email'], 'default'],
];

Вы также можете использовать более общий валидатор filter для выполнения более сложной фильтрации данных.

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

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

['age', 'trim'],
['age', 'default', 'value' => null],
['age', 'integer', 'integerOnly' => true, 'min' => 0],
['age', 'filter', 'filter' => 'intval', 'skipOnEmpty' => true],

Вышеупомянутый код выполнит следующие операции над вводом:

  1. Обрезает пробелы из входного значения.
  2. Убедитесь, что пустой ввод сохраняется как null в базе данных; мы различаем, является ли значение "не заданным" и фактическим значением 0. Если null не разрешено, вы можете установить здесь другое значение по умолчанию.
  3. Проверьте, является ли значение целым числом больше нуля, если оно не пустое. Нормальные валидаторы имеют $skipOnEmpty, установленным в true.
  4. Убедитесь, что значение является целым числом, например, преобразование строки '42' в целое число 42. Здесь мы устанавливаем $skipOnEmpty в true, что по умолчанию равно false для валидатора filter.

Обработка пустого ввода

Когда данные ввода отправляются из HTML-форм, вам часто нужно назначить некоторые значения по умолчанию для пустых полей. Вы можете сделать это, используя валидатор default. Например,

return [
    // set "username" and "email" as null if they are empty
    [['username', 'email'], 'default'],

    // set "level" to be 1 if it is empty
    ['level', 'default', 'value' => 1],
];

По умолчанию вход считается пустым, если его значение является пустой строкой, пустым массивом или null. Вы можете настроить логику обнаружения пустых значений по умолчанию, настроив свойство yii\validators\Validator::isEmpty() вызываемым PHP-объектом. Например,

    ['agree', 'required', 'isEmpty' => function ($value) {
        return empty($value);
    }]

Примечание: Большинство валидаторов не обрабатывают пустые вводы, если их свойство yii\validators\Validator::$skipOnEmpty принимает значение по умолчанию true. Они просто будут пропущены во время проверки, если соответствующие атрибуты получат пустой ввод. Из ядерных валидаторов только валидаторы captcha, default, filter, required, и trim будут обрабатывать пустые вводы.

Валидация ad hoc

Иногда вам нужно выполнить валидацию ad hoc для значений, которые не привязаны к какой-либо модели.

Если вам нужно выполнить только один тип валидации (например, проверка адресов электронной почты), вы можете вызвать метод validate() нужного валидатора, как показано ниже:

$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();

if ($validator->validate($email, $error)) {
    echo 'Email is valid.';
} else {
    echo $error;
}

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

Если вам нужно выполнить несколько проверок для нескольких значений, вы можете использовать yii\base\DynamicModel, который поддерживает объявление атрибутов и правил на лету. Его использование аналогично следующему:

public function actionSearch($name, $email)
{
    $model = DynamicModel::validateData(compact('name', 'email'), [
        [['name', 'email'], 'string', 'max' => 128],
        ['email', 'email'],
    ]);

    if ($model->hasErrors()) {
        // validation fails
    } else {
        // validation succeeds
    }
}

Метод yii\base\DynamicModel::validateData() создаёт экземпляр DynamicModel, определяет атрибуты, используя заданные данные (name и email в данном примере), а затем вызывает yii\base\Model::validate() с указанными правилами.

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

public function actionSearch($name, $email)
{
    $model = new DynamicModel(compact('name', 'email'));
    $model->addRule(['name', 'email'], 'string', ['max' => 128])
        ->addRule('email', 'email')
        ->validate();

    if ($model->hasErrors()) {
        // validation fails
    } else {
        // validation succeeds
    }
}

После валидации вы можете проверить, прошла ли валидация успешно, вызвав метод hasErrors(), а затем получить ошибки валидации из свойства errors, как вы делаете с обычной моделью. Вы также можете получить доступ к динамическим атрибутам, определенным через экземпляр модели, например, $model->name и $model->email.

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

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

Встроенные валидаторы

Встроенный валидатор определяется в терминах метода модели или анонимной функции. Подпись метода/функции:

/**
 * @param string $attribute the attribute currently being validated
 * @param mixed $params the value of the "params" given in the rule
 * @param \yii\validators\InlineValidator related InlineValidator instance.
 * This parameter is available since version 2.0.11.
 */
function ($attribute, $params, $validator)

Если атрибут не проходит валидацию, метод/функция должна вызвать yii\base\Model::addError(), чтобы сохранить сообщение об ошибке в модели, чтобы его можно было позже получить и отобразить пользователям.

Ниже приведены некоторые примеры:

use yii\base\Model;

class MyForm extends Model
{
    public $country;
    public $token;

    public function rules()
    {
        return [
            // an inline validator defined as the model method validateCountry()
            ['country', 'validateCountry'],

            // an inline validator defined as an anonymous function
            ['token', function ($attribute, $params, $validator) {
                if (!ctype_alnum($this->$attribute)) {
                    $this->addError($attribute, 'The token must contain letters or digits.');
                }
            }],
        ];
    }

    public function validateCountry($attribute, $params, $validator)
    {
        if (!in_array($this->$attribute, ['USA', 'Web'])) {
            $this->addError($attribute, 'The country must be either "USA" or "Web".');
        }
    }
}

Примечание: С версии 2.0.11 вы можете использовать yii\validators\InlineValidator::addError() для добавления ошибок. Таким образом, сообщение об ошибке может быть отформатировано с помощью yii\i18n\I18N::format() сразу. Используйте {attribute} и {value} в сообщении об ошибке для ссылки на метку атрибута (нет необходимости получать ее вручную) и значение атрибута соответственно:

$validator->addError($this, $attribute, 'The value "{value}" is not acceptable for {attribute}.');

Примечание: По умолчанию встроенные валидаторы не будут применяться, если их связанные атрибуты получают пустые входные данные или если они уже не прошли некоторые правила валидации. Если вы хотите убедиться, что правило всегда применяется, вы можете настроить свойства skipOnEmpty и/или skipOnError на false в объявлениях правил. Например:

[
    ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]

Отдельные валидаторы

Отдельный валидатор — это класс, расширяющий yii\validators\Validator или его дочерний класс. Вы можете реализовать его логику валидации, переопределив метод yii\validators\Validator::validateAttribute(). Если атрибут не проходит валидацию, вызовите yii\base\Model::addError(), чтобы сохранить сообщение об ошибке в модели, как вы делаете с встроенными валидаторами.

Например, встроенный валидатор выше можно перенести в новый класс [[components/validators/CountryValidator]].

namespace app\components;

use yii\validators\Validator;

class CountryValidator extends Validator
{
    public function validateAttribute($model, $attribute)
    {
        if (!in_array($model->$attribute, ['USA', 'Web'])) {
            $this->addError($model, $attribute, 'The country must be either "USA" or "Web".');
        }
    }
}

Если вы хотите, чтобы ваш валидатор поддерживал валидацию значения без модели, вы также должны переопределить yii\validators\Validator::validate(). Вы также можете переопределить yii\validators\Validator::validateValue() вместо validateAttribute() и validate(), потому что по умолчанию последние два метода реализуются путем вызова validateValue().

Ниже приведен пример того, как вы можете использовать этот класс валидатора в вашей модели.

namespace app\models;

use Yii;
use yii\base\Model;
use app\components\validators\CountryValidator;

class EntryForm extends Model
{
    public $name;
    public $email;
    public $country;

    public function rules()
    {
        return [
            [['name', 'email'], 'required'],
            ['country', CountryValidator::className()],
            ['email', 'email'],
        ];
    }
}

Валидация нескольких атрибутов

Иногда валидаторы включают несколько атрибутов. Рассмотрим следующую форму:

class MigrationForm extends \yii\base\Model
{
    /**
     * Minimal funds amount for one adult person
     */
    const MIN_ADULT_FUNDS = 3000;
    /**
     * Minimal funds amount for one child
     */
    const MIN_CHILD_FUNDS = 1500;

    public $personalSalary;
    public $spouseSalary;
    public $childrenCount;
    public $description;

    public function rules()
    {
        return [
            [['personalSalary', 'description'], 'required'],
            [['personalSalary', 'spouseSalary'], 'integer', 'min' => self::MIN_ADULT_FUNDS],
            ['childrenCount', 'integer', 'min' => 0, 'max' => 5],
            [['spouseSalary', 'childrenCount'], 'default', 'value' => 0],
            ['description', 'string'],
        ];
    }
}

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

Допустим, нам нужно проверить, достаточно ли семейный доход для детей. Мы можем создать встроенный валидатор validateChildrenFunds для этого, который будет выполняться только тогда, когда childrenCount больше 0.

Обратите внимание, что мы не можем использовать все проверенные атрибуты (['personalSalary', 'spouseSalary', 'childrenCount']) при подключении валидатора. Это связано с тем, что один и тот же валидатор будет выполняться для каждого атрибута (3 раза в общей сложности), а нам нужно выполнить его только один раз для всего набора атрибутов.

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

['childrenCount', 'validateChildrenFunds', 'when' => function ($model) {
    return $model->childrenCount > 0;
}],

Реализация validateChildrenFunds может быть такой:

public function validateChildrenFunds($attribute, $params)
{
    $totalSalary = $this->personalSalary + $this->spouseSalary;
    // Double the minimal adult funds if spouse salary is specified
    $minAdultFunds = $this->spouseSalary ? self::MIN_ADULT_FUNDS * 2 : self::MIN_ADULT_FUNDS;
    $childFunds = $totalSalary - $minAdultFunds;
    if ($childFunds / $this->childrenCount < self::MIN_CHILD_FUNDS) {
        $this->addError('childrenCount', 'Your salary is not enough for children.');
    }
}

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

Добавление ошибок

Добавление ошибок в случае нескольких атрибутов может варьироваться в зависимости от желаемого дизайна формы:

  • Выберите наиболее релевантное поле по вашему мнению и добавьте ошибку к его атрибуту:
$this->addError('childrenCount', 'Your salary is not enough for children.');
  • Выберите несколько важных релевантных атрибутов или все атрибуты и добавьте одно и то же сообщение об ошибке к ним. Мы можем сохранить сообщение в отдельной переменной перед передачей его в addError, чтобы сохранить код DRY.
$message = 'Your salary is not enough for children.';
$this->addError('personalSalary', $message);
$this->addError('wifeSalary', $message);
$this->addError('childrenCount', $message);

Или используйте цикл:

$attributes = ['personalSalary, 'wifeSalary', 'childrenCount'];
foreach ($attributes as $attribute) {
    $this->addError($attribute, 'Your salary is not enough for children.');
}
  • Добавьте общую ошибку (не связанную с конкретным атрибутом). Мы можем использовать не существующее имя атрибута для добавления ошибки, например, *, потому что существование атрибута не проверяется на этом этапе.
$this->addError('*', 'Your salary is not enough for children.');

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

<?= $form->errorSummary($model) ?>

Примечание: Создание валидатора, который проверяет сразу несколько атрибутов, подробно описано в справочнике по сообществу.

Валидация на стороне клиента

Валидация на стороне клиента на основе JavaScript желательна, когда пользователи вводят данные через HTML-формы, потому что она позволяет пользователям быстрее обнаруживать ошибки ввода и тем самым обеспечивает лучший пользовательский опыт. Вы можете использовать или реализовать валидатор, который поддерживает валидацию на стороне клиента в дополнение к валидации на стороне сервера.

Информация: Хотя валидация на стороне клиента желательна, она не является обязательной. Ее основная цель — предоставить пользователям лучший опыт. Подобно данным ввода от пользователей, вы никогда не должны доверять валидации на стороне клиента. По этой причине вы всегда должны выполнять валидацию на стороне сервера, вызывая yii\base\Model::validate(), как описано в предыдущих разделах.

Использование валидации на стороне клиента

Многие стандартные валидаторы поддерживают валидацию на стороне клиента «из коробки». Все, что вам нужно сделать, это просто использовать yii\widgets\ActiveForm для создания ваших HTML-форм. Например, LoginForm ниже объявляет два правила: одно использует требуемый стандартный валидатор, который поддерживается как на стороне клиента, так и на стороне сервера; другое использует validatePassword встроенный валидатор, который поддерживается только на стороне сервера.

namespace app\models;

use yii\base\Model;
use app\models\User;

class LoginForm extends Model
{
    public $username;
    public $password;

    public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],

            // password is validated by validatePassword()
            ['password', 'validatePassword'],
        ];
    }

    public function validatePassword()
    {
        $user = User::findByUsername($this->username);

        if (!$user || !$user->validatePassword($this->password)) {
            $this->addError('password', 'Incorrect username or password.');
        }
    }
}

HTML-форма, созданная следующим кодом, содержит два поля ввода username и password. Если вы отправите форму, не введя ничего, вы сразу увидите сообщения об ошибках, требующие ввода данных, без какого-либо взаимодействия с сервером.

<?php $form = yii\widgets\ActiveForm::begin(); ?>
    <?= $form->field($model, 'username') ?>
    <?= $form->field($model, 'password')->passwordInput() ?>
    <?= Html::submitButton('Login') ?>
<?php yii\widgets\ActiveForm::end(); ?>

За кулисами yii\widgets\ActiveForm будет читать правила валидации, объявленные в модели, и генерировать соответствующий JavaScript-код для валидаторов, которые поддерживают валидацию на стороне клиента. Когда пользователь изменяет значение поля ввода или отправляет форму, JavaScript-валидация на стороне клиента будет активирована.

Если вы хотите полностью отключить валидацию на стороне клиента, вы можете настроить свойство yii\widgets\ActiveForm::$enableClientValidation на false. Вы также можете отключить валидацию на стороне клиента отдельных полей ввода, настроив их свойство yii\widgets\ActiveField::$enableClientValidation на false. Когда enableClientValidation настроен как на уровне поля ввода, так и на уровне формы, предпочтение отдается первому.

Информация: С версии 2.0.11 все валидаторы, расширяющие yii\validators\Validator, получают параметры для клиента из отдельного метода — yii\validators\Validator::getClientOptions(). Вы можете использовать его:

  • если хотите реализовать собственную пользовательскую валидацию на стороне клиента, но оставить синхронизацию с параметрами валидатора на стороне сервера;
  • для расширения или настройки, чтобы соответствовать вашим конкретным потребностям:
public function getClientOptions($model, $attribute)
{
    $options = parent::getClientOptions($model, $attribute);
    // Modify $options here

    return $options;
}

Реализация валидации на стороне клиента

Чтобы создать валидатор, поддерживающий валидацию на стороне клиента, вы должны реализовать метод yii\validators\Validator::clientValidateAttribute(), который возвращает фрагмент JavaScript-кода, выполняющего валидацию на стороне клиента. Внутри JavaScript-кода вы можете использовать следующие предопределенные переменные:

  • attribute: имя атрибута, который проверяется.
  • value: значение, которое проверяется.
  • messages: массив, используемый для хранения сообщений об ошибках валидации для атрибута.
  • deferred: массив, в который можно добавлять отложенные объекты (объясняется в следующем подраздле).

В следующем примере мы создаем StatusValidator, который проверяет, является ли ввод допустимым статусом на основе имеющихся данных статуса. Валидатор поддерживает валидацию на стороне сервера и клиента.

namespace app\components;

use yii\validators\Validator;
use app\models\Status;

class StatusValidator extends Validator
{
    public function init()
    {
        parent::init();
        $this->message = 'Invalid status input.';
    }

    public function validateAttribute($model, $attribute)
    {
        $value = $model->$attribute;
        if (!Status::find()->where(['id' => $value])->exists()) {
            $model->addError($attribute, $this->message);
        }
    }

    public function clientValidateAttribute($model, $attribute, $view)
    {
        $statuses = json_encode(Status::find()->select('id')->asArray()->column());
        $message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        return <<<JS
if ($.inArray(value, $statuses) === -1) {
    messages.push($message);
}
JS;
    }
}

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

[
    ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
]

Подсказка: Если вам нужно работать с валидацией клиента вручную, т. е. динамически добавлять поля или выполнять пользовательскую логику пользовательского интерфейса, обратитесь к работе с ActiveForm через JavaScript в Yii 2.0 Cookbook.

Отложенная валидация

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

public function clientValidateAttribute($model, $attribute, $view)
{
    return <<<JS
        deferred.push($.get("/check", {value: value}).done(function(data) {
            if ('' !== data) {
                messages.push(data);
            }
        }));
JS;
}

В вышеприведенном примере переменная deferred предоставляется Yii, которая является массивом объектов отложенных задач. Метод $.get() jQuery создает объект отложенной задачи, который добавляется в массив deferred.

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

public function clientValidateAttribute($model, $attribute, $view)
{
    return <<<JS
        var def = $.Deferred();
        var img = new Image();
        img.onload = function() {
            if (this.width > 150) {
                messages.push('Image too wide!!');
            }
            def.resolve();
        }
        var reader = new FileReader();
        reader.onloadend = function() {
            img.src = reader.result;
        }
        reader.readAsDataURL(file);

        deferred.push(def);
JS;
}

Примечание: Метод resolve() должен вызываться после проверки атрибута. В противном случае основная проверка формы не завершится.

Для простоты, массив deferred оснащен сокращенным методом add(), который автоматически создаёт объект Deferred и добавляет его в массив deferred. Используя этот метод, вы можете упростить вышеприведённый пример следующим образом,

public function clientValidateAttribute($model, $attribute, $view)
{
    return <<<JS
        deferred.add(function(def) {
            var img = new Image();
            img.onload = function() {
                if (this.width > 150) {
                    messages.push('Image too wide!!');
                }
                def.resolve();
            }
            var reader = new FileReader();
            reader.onloadend = function() {
                img.src = reader.result;
            }
            reader.readAsDataURL(file);
        });
JS;
}

AJAX-валидация

Некоторые валидации могут быть выполнены только на стороне сервера, так как только сервер обладает необходимой информацией. Например, для проверки уникальности имени пользователя необходимо проверить таблицу пользователей на стороне сервера. В этом случае можно использовать AJAX-валидацию. Она запустит AJAX-запрос на заднем плане для валидации ввода, сохраняя тот же пользовательский опыт, что и обычная валидация на стороне клиента.

Для включения AJAX-валидации для отдельного поля ввода, настройте свойство enableAjaxValidation этого поля на true и укажите уникальную форму id:

use yii\widgets\ActiveForm;

$form = ActiveForm::begin([
    'id' => 'registration-form',
]);

echo $form->field($model, 'username', ['enableAjaxValidation' => true]);

// ...

ActiveForm::end();

Для включения AJAX-валидации для всей формы, настройте enableAjaxValidation на true на уровне формы:

$form = ActiveForm::begin([
    'id' => 'contact-form',
    'enableAjaxValidation' => true,
]);

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

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

if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
    Yii::$app->response->format = Response::FORMAT_JSON;
    return ActiveForm::validate($model);
}

Вышеприведённый код проверит, является ли текущий запрос AJAX. Если да, то он ответит на этот запрос, выполнив валидацию и вернув ошибки в формате JSON.

Информация: Также можно использовать Отложенную валидацию для выполнения AJAX-валидации. Однако, описанная здесь функция AJAX-валидации более систематична и требует меньше кодирования.

Когда и enableClientValidation и enableAjaxValidation установлены в true, запрос AJAX-валидации будет запущен только после успешной валидации на стороне клиента.

© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc-2.0/guide-input-validation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API