In the Writing your own validators recipe, we created a standalone validator. In this recipe, we will modify a validator to create extra client-side validation, which also checks the number of words.
Create a new application by using the Composer package manger, as described in the official guide at http://www.yiiframework.com/doc-2.0/guide-startinstallation.html.
@app/components/WordsValidator.php
as follows:<?php namespace appcomponents; use yiivalidatorsValidator; class WordsValidator extends Validator { public $size = 50; public $message = 'The number of words must be less than {size}'; public function validateValue($value) { preg_match_all('/(w+)/i', $value, $matches); if (count($matches[0]) > $this->size) { return [$this->message, ['size' => $this->size]]; } } public function clientValidateAttribute($model, $attribute, $view) { $message = strtr($this->message, ['{size}' => $this->size]); return <<<JS if (value.split(/w+/gi).length > $this->size ) { messages.push("$message"); } JS; } }
@app/models/Article.php
as follows:<?php namespace appmodels; use appcomponentsWordsValidator; use yiiaseModel; class Article extends Model { public $title; public function rules() { return [ ['title', 'string'], ['title', WordsValidator::className(), 'size' => 10], ]; } }
@app/controllers/ValidationController.php
as follows:<?php namespace appcontrollers; use appmodelsArticle; use Yii; use yiiwebController; class ValidationController extends Controller { public function actionIndex() { $model = new Article(); if ($model->load(Yii::$app->request->post()) && $model->validate()) { Yii::$app->session->setFlash('success', 'Model is valid'); } return $this->render('index', [ 'model' => $model, ]); } }
@app/views/validation/index.php
as follows:<?php use yiiootstrapActiveForm; use yiihelpersHtml; ?> <h1>Article form</h1> <?php if (Yii::$app->session->hasFlash('success')): ?> <div class="alert alert-success"><?= Yii::$app->session->getFlash('success'); ?></div> <?php endif; ?> <?php $form = ActiveForm::begin(); ?> <?= $form->field($model, 'title') ?> <div class="form-group"> <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?>
Run the validation controller by opening index.php?r=validation
. You will see an example of an incorrect value if you enter more than ten words:
If you enter fewer than ten words, client-side validation will be successful:
First, we created @app/components/WordsValidator.php
, which extends the @yiivalidatorsValidator
class, and added the newly-created validator class to the title attribute of the Article
model:
.. ['title', WordsValidator::className(), 'size' => 10], ..
Inside our validator, we've defined two special methods: validateValue()
and clientValidateAttribute()
.
Our validator class implements the validateValue()
method to support data validation out of the context of a data model. The second method just returns the JavaScript needed for performing client-side validation.
If we would like to hide validator realization, or want to control all validation processes only on the server-side, we can create a Deferred
object.
First, modify the WordsValidator
validator as follows:
<?php namespace appcomponents; use yiivalidatorsValidator; use yiihelpersUrl; class WordsValidator extends Validator { public $size = 50; public $message = 'The number of words must be less than {size}'; public function validateValue($value) { if (str_word_count($value) > $this->size) { return ['The number of words must be less than {size}', ['size' => $this->size]]; } return false; } public function clientValidateAttribute($model, $attribute, $view) { $url = Url::toRoute(['validation/check-words']); return <<<JS deferred.push($.get("$url", {words: value}).done(function(data) { if (!data.result) { messages.push(data.error); } })); JS; } }
In the preceding code, the deferred variable is provided by Yii, which is an array of Deferred
objects. The $.get() jQuery
method creates a Deferred
object, which is pushed to the deferred
array.
Second, add this checkWords
action to the validation
controller:
public function actionCheckWords() { Yii::$app->response->format = yiiwebResponse::FORMAT_JSON; $value = Yii::$app->getRequest()->get('words'); $validator = new WordsValidator([ 'size' => 10, ]); $result = $validator->validate($value, $error); return ['result' => $result,'error' => $error ]; }
3.145.74.54