Search code examples
phpvalidationyii2

Yii2: Standalone validation not triggering client validation


Validation functions don't work. Validation customs rules are not applied to the usernmane field

module dektrium/user
PHP 7.1
Yii 2.0.16

Already try all from here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation (Inline Validators and Standalone Validators)

Model Agent :

class Agent extends Profile
{
    public $username;
    public $password;
    public $password2;

    public function rules()
    {
        $rules = [
            ['username', AgentValidator::className()],// it's not work
            [['email'], 'email'], // it's work
            ['password2', 'compare', 'compareAttribute' => 'password', 'message' => 'Пароли должны совпадать'],//// it's work
        ];
        return array_merge(parent::rules(), $rules);
    }

}

AgentValidator.php

<?php
namespace app\components;
use yii\validators\Validator;

class AgentValidator extends  Validator
{
    public function validateAttribute($model, $attribute)
    {
      if (User::findOne(['username' => $this->$attribute]]) {
            $this->addError($attribute, 'Такой логин уже занят');

        }
    }
}

Solution

  • You are using standalone validator and you want the frontend validation to be working along with the backend so you need to override the yii\validators\Validator::clientValidateAttribute() in your Standalone validator AgentValidator, which returns a piece of JavaScript code that performs the validation on the client-side.

    Within the JavaScript code, you may use the following predefined variables:

    • attribute: the name of the attribute being validated.
    • value: the value being validated.
    • messages: an array used to hold the validation error messages for the attribute.
    • deferred: an array which deferred objects can be pushed into.

    You can go through the section Implementing Client Validation to read in detail.

    Apart from everything listed above you have a mistake in your validator code User::findOne(['username' => $this->$attribute]], you need to use $model->$attribute rather than $this->$attribute which will never get the exact value entered in the form. You might have mistakenly added it from the model.

    Your current validator should be like below

    <?php
    namespace app\components;
    use yii\validators\Validator;
    
    class AgentValidator extends  Validator
    {
        public $message='Такой логин уже занят';
    
        public function validateAttribute($model, $attribute)
        {
            if (User::findOne(['username' => $model->$attribute])!==null) 
            {
                $model->addError($attribute, $this->message);
            }
        }
    
        public function clientValidateAttribute($model, $attribute, $view) {
            //check if user exists
            $userExists = User::findOne(['username' => $model->$attribute])!==null;
    
            $message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    
            return <<<JS
                if($userExists){
                    messages.push($message);
                    return;
                }
    JS;
        }
    }