Yii学习笔记之四(表单验证 api 翻译)

1.表单验证


对于用户输入的所有数据,你不能信任,必须加以验证。
所有框架如此,对于yii 可以使用函数
 yii\base\Model::validate()  进行验证
他会返回boolean值的 true /false
如果验证未通过,可以使用  

yii\base\Model::$errors 属性进行处理,如下代码:

<?php
 
 //加载表单模型(绝对地址方式)
 /*如果上面引入 
   use app\models\ContactForm;
   则可以直接使用
   $model = new ContactForm;
 */
 $model = new \app\models\ContactForm;

// 接收用户填充的模型的字段 翻入属性
$model->attributes = \Yii::$app->request->post('ContactForm');

if ($model->validate()) {
    // 所有的输入验证通过
} else {
    // 验证失败: $errors 是一个包含所有错误信息的数组
    $errors = $model->errors;
}

?>

2. 声明规则


为了使验证函数 validate() 真正起作用,我们需要定一些验证
规则对应这些表单进行对应的验证,他会自动重写
yii\base\Model::rules() 方法
下面的例子讲述如何使用 rules

<?php

public function rules()
{
    return [
        // name, email, subject 和 body 属性必须填写
        [['name', 'email', 'subject', 'body'], 'required'],

        //email 必须是一个有效的邮箱地址
        ['email', 'email'],
    ];
}

//rule 返回值的格式

[
    // 必须的参数一, 指定必须遵守这个规则的某个属性或某些属性.
    // 对一个单个的属性,你能直接使用属性名
    // 不必将他放进一个数组 
    ['attribute1', 'attribute2', ...], //对于多个则可以放进一个数组

    // 必须的参数二, 指定规则的类型.
    // 他可以是一个类名, 验证方法的别名, 或者是验证方法名
    'validator',

    // 可选的参数三, 指定那一个场景使用这个规则
    // 如果没给, 意味着这个规则所有的场景都要将适用
    // 你可能也要配置 "except" 规则如果你想使用这个规则
    // to all scenarios except the listed ones
    'on' => ['scenario1', 'scenario2', ...],

    // 可选的参数, 定制额外的配置对验证项目
    'property1' => 'value1', 'property2' => 'value2', ...
]

?>

1> 对于每一个规则,你必须至少指定哪些属性的规则适用于什么是规则的类型。您可以在下列形式之一指定的规则类型:

(1) 核心验证的别名, 比如 required, in, date, 等等. 请参阅核心验证器为核心的校验器的完整列表。
http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html

(2) 在模型类model class中的验证方法的名字, 或一个匿名函数. 请参考内联验证器的详细信息.
http://www.yiiframework.com/doc-2.0/guide-input-validation.html#inline-validators

(3) 一个完全合格的验证器类名. 请参考标准验证器
http://www.yiiframework.com/doc-2.0/guide-input-validation.html#standalone-validators

一个规则可以用于一个或多个属性验证, 一个属性可以被一个或多个规则验证. 规则可以在某些情况下
只能通过选项指定的应用。如果您不选择指定,这意味着该规则将适用于所有情况。

2> 当 validate() 方法被调用的时候, 下面的步骤来解释验证的过程:

(1) 首先确定哪些属性应该通过获得从属性列表中进行验证
  yii\base\Model::scenarios() 使用当前的场景.这些属性被称为活跃属性。

(2) 确定哪些验证规则将会被使用通过获取 rule 列表从
 yii\base\Model::rules() 在当前的场景中使用. 这些规则被称为活跃规则。

(3) 用一个活跃的规则去验证每一个活跃的与对应规则相关联的属性.
   这些验证规则将根据他们列出的顺序顺序执行。


3. 定制错误信息


大多数验证有默认的错误信息,在验证失败的时候显示出来.例如 required 验证可以添加一句 "Username cannot be blank." 将会在username 没有填写的时候自动出现,如下:

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

?>

有些可能验证支持附加的额外的错误消息,以更准确地描述验证失败不同的原因。例如,数字验证器支持tooBig和tooSmall来描述验证失败时要验证的值分别为过大,过小。您可以配置这些错误信息就像一个验证规则配置验证的其他属性一样。


4. 验证事件


yii\base\Model::validate() 被调用的时候, 它将会自动调用两个自定义的方法:
http://www.yiiframework.com/doc-2.0/yii-base-model.html#beforeValidate()-detail

(1) yii\base\Model::beforeValidate(): 默认的实现会自动触发一个 yii\base\Model::EVENT_BEFORE_VALIDATE 事件. 你也可以重写这个方法或响应这个事件做一些预处理工作 (e.g. 正常化的数据输入) 在验证事件发生之前. 这个方法应该返回一个布尔值,指示验证是否应该继续与否。

(2) yii\base\Model::afterValidate(): 默认的实现会自动触发一个yii\base\Model::EVENT_AFTER_VALIDATE  事件.你也可以重写这个方法或响应这个事件在验证完成后做一些处理工作。


5. 条件验证


为了验证只有当某些条件适用属性, e.g. 一个属性的有效性依赖于另一个属性的值,你可以使用当属性来定义这样的条件。例如,'state' 只有当 'model'的属性值 'country' 为 'USA' 才成立

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

?>

这个 when 属性携带了一个PHP调用带着下面的签名:

<?php
/**
 * @param Model $model 正在被验证的model
 * @param string $attribute 正在被验证的属性
 * @return boolean 是否这个验证成功了
 */
function ($model, $attribute)

如果你也想支持客户端条件验证,你应该配置这个 whenClient 属性,以一个字符串形式传递
JavaScript 函数代码返回这个规则是否正确. 例如,

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

6. 数据过滤


用户输入的数据经常要预处理或过滤. 例如, 你可能想去掉username input两端的空格.
你可以使用验证规则去达到这个效果。

下面的例子就是去掉空格inputs 将孔的输入框转换为 nulls通过使用 trim 和 default两个核心验证器:

<?php
[
    [['username', 'email'], 'trim'],
    [['username', 'email'], 'default'],
]
?>
你可以展示更一般的过滤去完成更复杂的数据过滤.

就像你看到的,这些验证并不验证输入.相反,他们将输入通过程序返回给验证器.

7. 处理空的输入


当 HTML forms 表单数据被提交的时候, 你通常需要分配一些默认的值给这些 inputs 如果他们是空的话. 你也可以这么做使用默认的验证 如下代码:


<?php
[
    // 设置 "username" 和 "email" 值为 null 如果没填的话
    [['username', 'email'], 'default'],

    // 设置 "level" 为 1 如果为空的话 
    ['level', 'default', 'value' => 1],
]
?>

对于默认验证, 一个 input会被考虑是空的 如果他的值是一个空的字符串, 一个空的数组array 或者是一个 null. 你可以自定义这个默认值的逻辑通过配置
yii\validators\Validator::isEmpty() 属性作为一个 PHP调用. 例如:

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

提示: 大多数验证不会处理空的 inputs 如果他们的
   yii\base\Validator::skipOnEmpty 属性带着默认的 true 值. 仅仅是captcha, default, filter, required,trim 验证器会处理空的 inputs.


8. 特设验证

有时候你需要做一个特别验证,对某些没有绑定到任何 model的值

如果你只需要执行一个类型的验证 (e.g. 验证 email 地址), 你可以调用 validate() 方法去找到相应的验证,
就像想下面这样:


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

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

?>

提示: 并不是所有的验证器都支持这种类型验证. 一个例子是独特的核心验证,其目的是只用模式来工作。

如果需要对多个值执行多个验证,您可以使用
 yii\base\DynamicModel 可以同时声明属性 和 规则. 使用方式如下:

<?php

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

    if ($model->hasErrors()) {
        // 验证失败代码
    } else {
        // 验证成功代码
    }
}

?>

这个
 yii\base\DynamicModel::validateData()
方法创建了一个 DynamicModel 的实例,定义了使用给定的数据的属性(name 和 email 在这个例子中),
而且之后调用 yii\base\Model::validate() 携带给定的规则.

或者你可以使用  "classic" 语法进行上面的验证:

<?php
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()) {
        // 验证失败代码
    } else {
        // 验证成功代码
    }
}

?>

验证之后, 你可以检查验证是否成功不通过调用 hasErrors() 方法, 之后得到验证错误来自 errors属性,
就像你在处理一个正常的 model. 你也可以直接访问传统的属性通过 model 实例定义的,

例如, $model->name 和 $model->email.


10. 创建验证器

除了使用包含在Yii发布的 core validators 外, 你也可以创建自己的验证器. 你可以创建一个 内联 validators 独立 validators.

(1) Inline Validators(内置验证器)

一个 inline validator 是一个 model method 或一个匿名 function. 改 method/function 的原型是:

<?php
/**
 * @param string $attribute 当前被验证的属性
 * @param mixed $params 规则里给定的参数
 */
function ($attribute, $params)
?>

如果一个属性验证失败, 这个 method/function 将会调用
yii\base\Model::addError()
去保存错误信息在 model 以便于他能在遍历的时候反馈呈现给客户.

下面是给定的例子:

<?php
use yii\base\Model;

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

    public function rules()
    {
        return [
            // 一个 inline validator 定义作为一个 model 方法 validateCountry()
            ['country', 'validateCountry'],

            // 一个 inline validator 定义作为一个匿名 function
            ['token', function ($attribute, $params) {
                if (!ctype_alnum($this->$attribute)) { 判断是否是字母和数字或字母数字的组合
                    $this->addError($attribute, 'The token must contain letters or digits.');
                }
            }],
        ];
    }

    public function validateCountry($attribute, $params)
    {
        if (!in_array($this->$attribute, ['USA', 'Web'])) {
            $this->addError($attribute, 'The country must be either "USA" or "Web".');
        }
    }
}
?>
提示: 如果他们的相关属性接收空的输入或者他们已经验证失败一些规则通过 default, inline validators 将不会被用。
如果你想确保一个规则始终适用,您可以配置 skipOnEmpty 和/或 skipOnError性质是 false 的规则声明。例如:

<?php
[
    ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]
?>

(2) Standalone Validators (单独验证器)
一个 standalone validator 是一个类扩展
yii\validators\Validator 或者是他的子类

你可以实现他的验证逻辑通过重写
yii\validators\Validator::validateAttribute() 方法.

如果一个属性验证失败, 调用
yii\base\Model::addError()
去保存错误信息在 model 里, 就像上面 的 inline validators 所做的. 例如,

<?php

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".');
        }
    }
}

?>
如果你想你的验证器支持验证一个model外的值,你也应该重写
yii\validators\Validator::validate().
你可能也要重写
yii\validators\Validator::validateValue() 代替 validateAttribute() 和 validate()
因为默认的后两种方法通过调用 validateValue() 实现.

11. 客户端验证


客户端验证基于 JavaScript .

Info:  yii\base\Model::validate(),
使用  yii\widgets\ActiveForm 创建你的 HTML forms.
例如, LoginForm 需要声明两条规则:
      A. 必填 required; 既支持客户端 又支持服务端
      B. 密码验证 validatePassword 使用 inline validator 只支持服务端

<?php
namespace app\models;

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

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

    public function rules()
    {
        return [
            // username 和 password 都不能为空
            [['username', 'password'], 'required'],

            // password 通过 validatePassword() 验证
            ['password', 'validatePassword'],
        ];
    }

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

        if (!$user || !$user->validatePassword($this->password)) {
            $this->addError('password', 'Incorrect username or password.');
        }
    }
}
?>
下面的代码创建俩表单 username 和 password.
如果你提交 form 的时候没有输入任何东西, 你会发现 requiring 的错误信息.

<?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
会读取定义在 model 中的验证规则 然后生成相近的 JavaScript 代码用来支持相应的客户端代码.当一个用户改变输入框input 得值 或者 提交submit 表单form, 客户端的javascript会自动触发.

如果你想完全关闭客户端验证, 你可以配置:
yii\widgets\ActiveForm::$enableClientValidation 的属性为 false.
你也可以关闭部分的输入表单验证通过配置他们的
yii\widgets\ActiveField::$enableClientValidation 的属性为 false.

实现客户端验证
为了创建一个支持客户端的验证, 你需要实现
yii\validators\Validator::clientValidateAttribute() 方法
返回在客户端执行的部分 JavaScript 代码.
在 JavaScript 代码里, 你可以使用下面预定义的变量:

attribute: 即将被验证的属性.
value: 被验证的值.
messages: 一个 array 用于处理 attribute 验证的错误信息.
deferred: 一个 array 放入延期的对象.
在下面的例子中,我们创建一个StatusValidator这验证如果输入是针对现有的状态数据的有效状态输入。
验证器同时支持服务器端和客户端验证

<?php
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);
        //返回js代码
		return <<<JS
if (!$.inArray(value, $statuses)) {
    messages.push($message);
}
JS;
    }
}

?>

小贴士: The above code is given mainly to demonstrate how to support client-side validation. 在实践中, 你可以用核心验证器达到相同的效果. 你也可以像下面一样填写验证规则:

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

?>

12. 延迟验证

如果你需要执行一个客户端异步验证, 你可以创建一个延迟对象集. 例如, 去执行一个 AJAX 验证, 你可以使用下面的代码:

<?php
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 object 并被放入 deferred 数组里.

你也可以精确的创建一个 Deferred object 接着调用他的 resolve() 当异步回调函数被触发的时候.
下面的示例演示如何验证在客户端上传的图像文件的尺寸。

<?php
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 object 然后 将他添加到
deferred 数组. 使用这个方法, 你能将上面的代码简化成下面的:

<?php
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;
}

?>

13. AJAX 验证


去启用 AJAX 为整个form, 你不得不设置
yii\widgets\ActiveForm::$enableAjaxValidation 属性值为 true
而且要指定id 成为一个唯一的 form 定义:

<?php $form = yii\widgets\ActiveForm::begin([
    'id' => 'contact-form',
    'enableAjaxValidation' => true,
]); ?>
对于部分字段的ajax 验证是否启用,你可以设置对应属性的
yii\widgets\ActiveField::$enableAjaxValidation 属性.

您还需要准备服务器端代码,以便它可以处理Ajax验证请求。这可以通过一个代码段像在控制器动作以下来实现:

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

?>
上面的代码检查当前的请求是否是一个 AJAX. 如果是, 他将响应这个请求运行验证然后返回错误信息以JSON格式.

信息: 你也可以使用 Deferred 去执行 AJAX 验证. 但是,这里所描述的AJAX验证的特点是更系统,
更需要较少的编码工作。





















  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值