创建一个自定义客户端的校验器

自定义校验器小节中,我们创建了一个独立的校验器。在本小节中,我们将会修改一个校验器来创建额外的客户端校验,它也会检查单词的数量。

准备

按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。

如何做…

  1. 创建@app/components/WordsValidator.php
  1. <?php
  2. namespace app\components;
  3. use yii\validators\Validator;
  4. class WordsValidator extends Validator
  5. {
  6. public $size = 50;
  7. public $message = 'The number of words must be less than {size}';
  8. public function validateValue($value)
  9. {
  10. preg_match_all('/(\w+)/i', $value, $matches);
  11. if (count($matches[0]) > $this->size) {
  12. return [$this->message, ['size' => $this->size]];
  13. }
  14. }
  15. public function clientValidateAttribute($model, $attribute, $view)
  16. {
  17. $message = strtr($this->message, ['{size}' => $this->size]);
  18. return <<<JS
  19. if (value.split(/\w+/gi).length > $this->size ) {
  20. messages.push("$message");
  21. }
  22. JS;
  23. }
  24. }
  1. 创建@app/models/Article.php
  1. <?php
  2. namespace app\models;
  3. use app\components\WordsValidator;
  4. use yii\base\Model;
  5. class Article extends Model
  6. {
  7. public $title;
  8. public function rules()
  9. {
  10. return [
  11. ['title', 'string'],
  12. ['title', WordsValidator::className(), 'size' => 10],
  13. ];
  14. }
  15. }
  1. 创建@app/controllers/ValidationController.php
  1. <?php
  2. namespace app\controllers;
  3. use app\models\Article;
  4. use Yii;
  5. use yii\web\Controller;
  6. class ValidationController extends Controller
  7. {
  8. public function actionIndex()
  9. {
  10. $model = new Article();
  11. if ($model->load(Yii::$app->request->post()) &&
  12. $model->validate()) {
  13. Yii::$app->session->setFlash('success', 'Model is valid');
  14. }
  15. return $this->render('index', [
  16. 'model' => $model,
  17. ]);
  18. }
  19. }
  1. 创建@app/views/validation/index.php
  1. <?php
  2. use yii\bootstrap\ActiveForm;
  3. use yii\helpers\Html;
  4. ?>
  5. <h1>Article form</h1>
  6. <?php if (Yii::$app->session->hasFlash('success')): ?>
  7. <div class="alert alert-success"><?= Yii::$app->session->getFlash('success'); ?></div>
  8. <?php endif; ?>
  9. <?php $form = ActiveForm::begin(); ?>
  10. <?= $form->field($model, 'title') ?>
  11. <div class="form-group">
  12. <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
  13. </div>
  14. <?php ActiveForm::end(); ?>

工作原理…

打开index.php?r=validation运行校验控制器。如果你输入了超过10个单词,你将会看到一个错误:

创建一个自定义客户端的校验器 - 图1

如果输入的少于10个单词,客户端校验是成功的:

创建一个自定义客户端的校验器 - 图2

首先,我们创建了@app/componets/WordsValidator.php,它继承了@yii\validators\Validator类,添加新创建的校验器到Article模型的标题属性:

  1. ..
  2. ['title', WordsValidator::className(), 'size' => 10],
  3. ..

在我们的校验器内部,我们已经定义了两个特殊的方法:validatorValue()clientValidatorAttribute()

我们的校验器类实现了validatorValue()方法来支持数据模型之外的数据校验。第二个方法只是返回客户端需要的JavaScript。

更多…

如果我们希望隐藏校验器实现,或者希望控制所有的校验过程在服务端,我们可以创建一个Deferred对象。

首先,修改WordsValidator校验器:

  1. <?php
  2. namespace app\components;
  3. use yii\validators\Validator;
  4. use yii\helpers\Url;
  5. class WordsValidator extends Validator
  6. {
  7. public $size = 50;
  8. public $message = 'The number of words must be less than {size}';
  9. public function validateValue($value)
  10. {
  11. if (str_word_count($value) > $this->size) {
  12. return ['The number of words must be less than {size}',
  13. ['size' => $this->size]];
  14. }
  15. return false;
  16. }
  17. public function clientValidateAttribute($model, $attribute, $view)
  18. {
  19. $url = Url::toRoute(['validation/check-words']);
  20. return <<<JS
  21. deferred.push($.get("$url", {words:
  22. value}).done(function(data) {
  23. if (!data.result) {
  24. messages.push(data.error);
  25. }
  26. }));
  27. JS;
  28. }
  29. }

在先前的代码中,deferred变量由Yii提供,它是Deferred对象组成的一个数组,$.get()JQuery方法创建一个Deferred对象,它被放入了deferred数组中。

第二,添加checkWords动作到validation控制器中:

  1. public function actionCheckWords()
  2. {
  3. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  4. $value = Yii::$app->getRequest()->get('words');
  5. $validator = new WordsValidator([
  6. 'size' => 10,
  7. ]);
  8. $result = $validator->validate($value, $error);
  9. return ['result' => $result,'error' => $error
  10. ];
  11. }

参考

欲了解更多信息,参考如下地址: