Yii2具有强大的表单验证功能,能用好表单验证,用户输入就基本掌握了,在这里我和各位聊聊Yii2的服务器端验证器
。
所谓服务器端验证器
,就是在model
或AR(Active Record)
中定义,使用validate()
或save()
函数进行验证的验证器。
关于输入验证Yii2官网文档是这样说的:
As a rule of thumb, you should never trust the data received from end users and should always validate it before putting it to good use.
摘自:http://www.yiiframework.com/doc-2.0/guide-input-validation.html
这句话的意思是任何从客户端过来的数据都要进行验证!
这里所说的验证主要是指服务器端验证
,所以说服务器端验证
在输入处理过程中是必不可少的!
服务器端验证代码结构大概是这样:
if($model->validate()){//或if($model->save()){
//验证通过后执行的代码,如数据存储等
}else{
//显示验证错误信息
$this->errorDisplay($model->getErrors());
}
这段代码通常是存放在Controller
的Action
中的,请参见后面的源码。
在服务器端进行数据验证通常有两种调用方式:
1、$model->validate()
此方法将根据rules()中定义的验证规则对所有数据进行有效性检测,检测通过,则进行数据存储等后续操作;验证未通过则显示错误信息。$this->errorDisplay()
调用自CommonController
,请参见:
http://www.jianshu.com/p/5d2c42166702
2、$model->save()
此方法在AR(Active Record)中经常使用到,它默认调用了$model->validate(),验证通过后则直接进行数据存储,返回true;验证失败则不进行数据存储,返回false,错误信息存储在$model->errors中。顺便提一下,$model->save(false)是AR不进行数据验证的存储操作,通常嵌套于$model->validate()通过后的内层,即:
if($model->validate()){//此处的$model是一个Active Record(AR)
//AR验证通过,存储时无需再进行二次验证
if ($model->save(false)) {
//数据存储成功
}else{
return $this->error('Sorry,Data save fail!');
}
}
我们先来看一看服务器端验证的效果是什么样子?
上图是
客户端验证
的效果,即,将ActiveForm的enableClientValidation
设置为true
时的验证效果:验证通过则输入框变为绿色
,验证未通过则输入框变为红色
并在其下方显示错误信息。上图是
服务器端验证
的效果,即,将ActiveForm的enableClientValidation
设置为false
时,由$model->validate()
验证失败后显示出来的错误信息页面。注意:要显示上图页面效果,请确保你的
YII_DEBUG=true
在此需要说明的是:
1、为了展现服务器端验证的效果,所以在此专门把enableClientValidation
设置为false
,开发时无需
进行此项设置。
2、只要调用$model->validate()
或AR的$model->save()
方法,Yii2就会进行服务器端的数据验证,无需
做额外的参数设置。
服务器端验证的规则在哪里编写呢?与客户端验证一样,服务器端验证的规则也是在rules()
中编写。而且,一条同样的验证规则,只需要编写一次
就可以了,Yii2会自动在客户端
、服务器端
以及Ajax验证
中自行调用,是不是感觉Yii2框架很神奇呢!在马化腾写程序的年代可是要在三处分别编写代码的:(
我们一起来看一看rules()
中验证规则,请仔细阅读代码中的注释
:
public function rules() {
return [
//三项都是必填项(required)
[['countryName','countryAbbr','continent'],'required'],
//对表单项进行去掉首尾空格的处理(trim)
[['countryName','countryAbbr','continent'],'trim'],
//对'countryName'进行唯一性检测(unique),即此项输入值在数据库是唯一的(不存在此值),否则报错
['countryName', 'unique',
//设置此项要使用AR(Active Record)类,只有AR类才可以对数据库直接进行查询,Model默认是没有此功能的
'targetClass' => '\frontend\models\Country',
//本输入项'countryName'对应查询的是Country表中的name字段
'targetAttribute' => 'name',
//使用了一个过滤器,即andWhere(['continent' => 'Europe'])
'filter' => ['continent' => 'Europe'],
//验证未通过时要显示的信息
'message' => '输入的国家名称已在Europe中存在!',
],
//对'countryName'进行存在检测(exist),即此项输入值在数据库是存在的,否则报错
['countryAbbr', 'exist',
'targetClass' => '\frontend\models\Country',
'targetAttribute' => 'code',
'filter' => ['continent' => 'Europe'],
'message' => 'Europe没有这样的国家简称',
],
//对'continent'进行范围检测,只能输入所列范围(range)5项中的之一项,否则报错
['continent','in','range'=>['Europe','Asia','South America','North America','Oceania'],'message' => '没有这样的大洲'],
];
}
本例中使用到的required
、trim
、unique
、exist
,都是Yii2提供的验证器的别名
(简称),想要知道这些验证器的全称
,可以调用以下代码:
$aa=\yii\validators\Validator::$builtInValidators;
var_dump($aa);
Yii2提供了23个核心验证器
,请参阅文档:
http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html
本文所涉及到的程序源码
:
文件位置:D:\phpwork\advanced\frontend\controllers\DemoController.php
<?php
namespace frontend\controllers;
use Yii;
class DemoController extends CommonController{
public function actionForm2() {
$model=new \frontend\models\Form2();
if ($model->load(Yii::$app->request->post())) {
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return \yii\bootstrap\ActiveForm::validate($model);
}
if($model->validate()){
if ($model->save()) {
return $this->render('form2a',['model'=>$model]);
}else{
return $this->error('Sorry,Data save fail!');
}
}else{
return $this->errorDisplay($model->getErrors());
}
}else{
$countries=\frontend\models\Country::find()->asArray()->all();
return $this->render('form2',['model'=>$model,'countries'=>$countries]);
}
}
}
其中errorDisplay()
方法是调用自CommonController
,请参见:
http://www.jianshu.com/p/5d2c42166702
文件位置:D:\phpwork\advanced\frontend\models\Form2.php
<?php
namespace frontend\models;
use Yii;
class Form2 extends \yii\base\Model{
public $countryName,$countryAbbr,$continent;
public function attributeLabels() {
return [
'countryName'=>'国家名称',
'countryAbbr'=>'国家简称',
'continent'=>'所属大洲'
];
}
public function rules() {
return [
//三项都是必填项
[['countryName','countryAbbr','continent'],'required'],
//对表单项进行去掉首尾空格的处理
[['countryName','countryAbbr','continent'],'trim'],
//对'countryName'进行唯一性检测(unique),即此项输入值在数据库是唯一的(不存在此值),否则报错
['countryName', 'unique',
//设置此项要使用AR(Active Record)类,只有AR类才可以对数据库直接进行查询,Model默认是没有此功能的
'targetClass' => '\frontend\models\Country',
//本输入项'countryName'对应查询的是Country表中的name字段
'targetAttribute' => 'name',
//使用了一个过滤器,即andWhere(['continent' => 'Europe'])
'filter' => ['continent' => 'Europe'],
//验证未通过时要显示的信息
'message' => '输入的国家名称已在Europe中存在!',
],
//对'countryName'进行存在检测(exist),即此项输入值在数据库是存在的,否则报错
['countryAbbr', 'exist',
'targetClass' => '\frontend\models\Country',
'targetAttribute' => 'code',
'filter' => ['continent' => 'Europe'],
'message' => 'Europe没有这样的国家简称',
],
//对'continent'进行范围检测,只能输入所列范围(range)5项中的之一项,否则报错
['continent','in','range'=>['Europe','Asia','South America','North America','Oceania'],'message' => '没有这样的大洲'],
];
}
public function save() {
return true;
}
}
文件位置:D:\phpwork\advanced\frontend\views\demo\form2.php
<?php
use yii\bootstrap\ActiveForm;
use yii\helpers\Html;
?>
<div class="panel panel-warning">
<div class="panel-heading">
<div class="panel-title">
二、Yii2的表单验证——服务器端验证的验证器
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-7">
<?php
$form = ActiveForm::begin([
'enableClientValidation' => false,
// 'enableClientValidation' => true,
//'enableAjaxValidation'=>false,
// 'enableAjaxValidation'=>true,
'layout' => 'horizontal',
]);
?>
<?=$form->field($model,'countryName')->textInput()?>
<?=$form->field($model,'countryAbbr',['inputOptions'=>['class'=>'form-control']])->textInput()?>
<?=$form->field($model,'continent')->textInput()?>
<div class="row">
<div class='col-md-2 col-md-offset-2'><?= Html::submitButton('提 交 ', ['class' => 'btn btn-primary form-control']) ?></div>
<div class='col-md-2 col-md-offset-2'><?= Html::resetButton('重 置 ', ['class' => 'btn btn-default form-control'])?></div>
</div>
<?php ActiveForm::end(); ?>
</div>
<div class="col-md-5">
<TABLE class="table table-bordered country">
<TR >
<TD style="width:60px;">序号</TD>
<TD>国家</TD>
<TD style="width:60px;">简称</TD>
<TD>大洲</TD>
</TR>
<?php
foreach ($countries as $k=>$item) {
echo '<TR><TD>'.($k+1).'</TD><TD>'.$item['name'].'</TD><TD>'.$item['code'].'</TD><TD>'.$item['continent'].'</TD></TR>';
}
?>
</TABLE>
</div>
</div>
</div>
</div>
文件位置:D:\phpwork\advanced\frontend\views\demo\form2a.php
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
?>
<div class="panel panel-warning">
<div class="panel-heading">
<div class="panel-title">
二、Yii2的表单验证——服务器端验证的验证器(提交数据的显示)
</div>
</div>
<div class="panel-body" style="height:500px;">
<?php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'countryName',
'countryAbbr',
'continent',
],
'template' => '<tr><th class="text-right" style="width:150px;">{label}</th><td>{value}</td></tr>',
]);
?>
<button onclick="history.back()" class="btn btn-default">返 回</button>
</div>
</div>
Country
类是Yii2官网实例中的一个类,请参照官网文档自行构建。
本例涉及的数据库表country
,比官网实例中多了一个字段:continent
,手动加上亦可:
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`continent` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',24016400,'Oceania');
INSERT INTO `country` VALUES ('BR','Brazil',205722000,'South America');
INSERT INTO `country` VALUES ('CA','Canada',35985751,'North America');
INSERT INTO `country` VALUES ('CN','China',1375210000,'Asia');
INSERT INTO `country` VALUES ('DE','Germany',81459000,'Europe');
INSERT INTO `country` VALUES ('FR','France',64513242,'Europe');
INSERT INTO `country` VALUES ('GB','United Kingdom',65097000,'Europe');
INSERT INTO `country` VALUES ('IN','India',1285400000,'Asia');
INSERT INTO `country` VALUES ('RU','Russia',146519759,'Europe');
INSERT INTO `country` VALUES ('US','United States',322976000,'North America');
欢迎深入阅读:
一处编写,三处运行的Yii2表单验证
(全文完)