Using custom validators with ActiveForm in Yii2

爱⌒轻易说出口 提交于 2019-12-11 17:04:43

问题


I want to make custom validation function like built-in validation required. I have example code here:

Model:

use yii\base\Model;

class TestForm extends Model
{
    public $age;
    public function rules(){
        return [
            ['age', 'my_validation']
        ];
    }
    public function my_validation(){
        //some code here
    }
}

View:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;


$this->title = 'test';
?>
<div style="margin-top: 30px;">

    <?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'age')->label("age") ?>
    <div class="form-group">
        <?= Html::submitButton('submit', ['class' => 'btn btn-primary']) ?>
    </div>
    <?php ActiveForm::end(); ?>

</div>

Controller:

use app\models\form\TestForm;
use yii\web\Controller;

class TestController extends Controller
{
    public function actionIndex(){
        $model = new TestForm();

        if($model->load(\Yii::$app->request->post())){
            return $this->render('test', array(
                'model'=>$model,
                'message'=>'success'
            ));
        }
        return $this->render('test', array('model'=>$model));
    }
}

in this example I have a field for age and this my_validation function should check if age is over 18 before submit and throw error if age is under 18. This validation should be processed by ajax like it is in case of required rule if you try to submit empty field.


回答1:


Although you can use Conditional Validators when and whenClient too in your scenario but I would recommend using a more sophisticated way which is to define a custom validator because according to the docs

To create a validator that supports client-side validation, you should implement the yii\validators\Validator::clientValidateAttribute() method 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 (explained in the next subsection).

So what you need to do is create a validator and add it to your rules against the field you want.

You need to be careful copying the following code IF you haven't provided the actual model name and update the field names accordingly.

1) First thing to do is to update the ActiveForm widget to the following

$form = ActiveForm::begin([
    'id' => 'my-form',
    'enableClientValidation' => true,
    'validateOnSubmit' => true,
]);

2) Change your model rules() function to the following

public function rules()
    {
        return [
            [['age'], 'required'],
            [['age'], \app\components\AgeValidator::className(), 'skipOnEmpty' => false, 'skipOnError' => false],
        ];
    }

3) Remove the custom validation function my_validation() from your model i hope you are checking the age limit in it to be 18+ we will move that logic into the validator.

Now create a file AgeValidator.php inside components directory, if you are using the basic-app add the folder components inside the root directory of the project if it does not exist create a new one, and copy the following code inside.

BUT

I have assumed the name of the Model that is provided by you above so if it not the actual name you have to update the field name inside the javascript statements within clientValidateAttribute function you see below in the validator because the id attribute of the fields in ActiveForm is generated in a format like #modelname-fieldname (all small case) so according to above given model, it will be #testform-age do update it accordingly otherwise the validation wont work. And do update the namespace in the validator below and in the model rules() if you plan to save it somewhere else.

<?php

namespace app\components;

use yii\validators\Validator;

class AgeValidator extends Validator
{

    public function init()
    {
        parent::init();
        $this->message = 'You need to be above the required age 18+';
    }

    public function validateAttribute($model, $attribute)
    {

        if ($model->$attribute < 18) {
            $model->addError($attribute, $this->message);
        }
    }

    public function clientValidateAttribute($model, $attribute, $view)
    {

        $message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        return <<<JS

if (parseInt($("#testform-age").val())<18) {
    messages.push($message);
}
JS;
    }

}


来源:https://stackoverflow.com/questions/48628100/using-custom-validators-with-activeform-in-yii2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!