PHP YII框架开发小技巧之模型(models)中rules自定义验证规则


Posted in PHP onNovember 16, 2015

YII的models中的rules部分是一些表单的验证规则,对于表单验证十分有用,在相应的视图(views)里面添加了表单,在表单被提交之前程序都会自动先来这里面的规则里验证,只有通过对其有效的限制规则后才能被提交,可以很有效地保证表单安全和信息的有效性。还是给大家具体说明一下:

以下是视图(views)部分的简单代码:

<?php $form=$this->beginWidget('CActiveForm', array( 
  'id'=>'tag-form', 
  'enableAjaxValidation'=>false, 
)); ?> 
  <div class="row"> 
    <?php echo $form->labelEx($model,'tagname'); ?> 
    <?php echo $form->textField($model,'tagname',array('size'=>20,'maxlength'=>32)); ?> 
  </div> 
  <div class="row"> 
    <?php echo $form->labelEx($model,'tagtype'); ?> 
    <?php echo $form->radioButtonList($model,'tagtype'array(1=>"普通TAG",2=>"系统默认TAG"),array('separator'=>'','labelOptions'=>array('class'=>'tagtypelabel'))); ?> 
  </div> 
  <?php echo $form->errorSummary($model); ?> 
  <div class="row buttons"> 
    <?php echo CHtml::submitButton($model->isNewRecord ? '添加' : '修改'); ?> 
  </div> 
<?php $this->endWidget(); ?>

模型(models)中rules部分的简单代码:

public function rules() 
{ 
  return array( 
    array('tagname,tagtype', 'required'), 
    array('tagtype', 'numerical', 'integerOnly'=>true), 
    array('tagname', 'length', 'max'=>32), 
    array('tagname', 'match', 'pattern'=>'/^[\x{4e00}-\x{9fa5}A-Za-z0-9]+$/u', 
        'message'=>'标签不合法,必须为汉字、字母或者数字!'), 
    array('tagname', 'checktagname', 'on'=>'create,update'),//插入TAG时检查是否已经存在该tag 
    array('tagid, tagname, tagtype', 'safe', 'on'=>'search'), 
  ); 
}

系统默认有这些验证规则:

boolean : CBooleanValidator 的别名, 确保属性的值是CBooleanValidator::trueValue 或 CBooleanValidator::falseValue . 
captcha : CCaptchaValidator 的别名,确保了特性的值等于 CAPTCHA 显示出来的验证码. 
compare : CCompareValidator 的别名, 确保了特性的值等于另一个特性或常量. 
email : CEmailValidator 的别名,确保了特性的值是一个有效的电邮地址. 
default : CDefaultValueValidator 的别名, 为特性指派了一个默认值. 
exist : CExistValidator 的别名, 确保属性值存在于指定的数据表字段中. 
file : CFileValidator 的别名, 确保了特性包含了一个上传文件的名称. 
filter : CFilterValidator 的别名, 使用一个filter转换属性. 
in : CRangeValidator 的别名, 确保了特性出现在一个预订的值列表里. 
length : CStringValidator 的别名, 确保了特性的长度在指定的范围内. 
match : CRegularExpressionValidator 的别名, 确保了特性匹配一个正则表达式. 
numerical : CNumberValidator 的别名, 确保了特性是一个有效的数字. 
required : CRequiredValidator 的别名, 确保了特性不为空. 
type : CTypeValidator 的别名, 确保了特性为指定的数据类型. 
unique : CUniqueValidator 的别名, 确保了特性在数据表字段中是唯一的. 
url : CUrlValidator 的别名, 确保了特性是一个有效的路径.

基本上还是比较全面的,一般的都够用了,但是还是有时候有的验证需要自定义。就以上面的代码为例,我们在添加TAG时需要检查系统之前是否已经存在这个TAG,如果存在则不让用户添加。这个就需要在添加之前去查询数据库,看该TAG是否已经存在,这里我们就需要自定一个验证规则了。

关键有一下两个步骤:

1、在rules中 添加代码:array('tagname', 'checktagname', 'on'=>'create,update'),//插入TAG时检查是否已经存在该tag

注:我在其中用了 'on'=>'create,update',所以这个验证规则之对create,update场景生效

2、在该模型(models)中添加验证函数:

public function checktagname($attribute,$params){ 
  $oldtag = Tag::model()->findByAttributes(array('tagname'=>$this->tagname)); 
  if($oldtag->tagid > 0){ 
    $this->addError($attribute, '该TAG已经存在!'); 
  } 
}

其中需要说明的是:

(1)该验证函数的参数必须是($attribute,$params),不能缺少其中任何一个;

(2)$this->addError($attribute, '该TAG已经存在!');这个是你想要在视图中输出的错误提示信息。

就是这么简单,有了这个方法,表单验证的各种想要的规则就都可以自定义了。

下面给大家介绍Yii自定义验证规则

最简单的定义验证规则的方法是在使用它的模型(model)内部定义。

比方说,你要检查用户的密码是否足够安全.

通常情况下你会使用 CRegularExpression 方法验证,但为了本指南,我们假设不存在此验证方法.

首先在模型(model)中添加两个常量

const WEAK = 0;
const STRONG = 1;然后在模型(model)的 rules 方法中设置:

/**
 * @return array validation rules for model attributes.
 */
public function rules()
{
  return array(
    array('password', 'passwordStrength', 'strength'=>self::STRONG),
  );
}

确保你写的规则不是一个已经存在的规则,否则将会报错.

现在要做的是在模型(model)中创建一个名称为上面填写的规则的方法(即 passwordStrength)。

/**
 * check if the user password is strong enough
 * check the password against the pattern requested
 * by the strength parameter
 * This is the 'passwordStrength' validator as declared in rules().
 */
public function passwordStrength($attribute,$params)
{
  if ($params['strength'] === self::WEAK)
    $pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/'; 
  elseif ($params['strength'] === self::STRONG)
    $pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/'; 
    
  if(!preg_match($pattern, $this->$attribute))
   $this->addError($attribute, 'your password is not strong enough!');
}

刚才创建的方法需要两个参数:* $attribute 需要验证的属性* $params 在规则中自定义的参数

在模型的 rules 方法中我们验证的是 password 属性,所以在验证规则中需要验证的属性值应该是 password.

在 rules 方法中我们还设置了自定义的参数 strength,它的值将会放到 $params 数组中.

你会发现在方法中我们使用了 CModel::addError().

添加错误接受两个参数:第一个参数是在表单中显示错误的属性名,第二个参数时显示的错误信息 。

完整的方法:继承 CValidator 类

如果你想把规则使用在多个模型(model)中,最好的方法时继承 CValidator 类。

继承这个类你可以使用像 CActiveForm::$enableClientValidation (Yii 1.1.7 版本后可用) 类似的其他功能。

创建类文件

首先要做的是创建类文件.最好的方法时类的文件名和类名相同,可以使用 yii 的延迟加载(lazy loading)功能。

让我们在应用(application)的扩展(extensiions)目录(在 protected 文件夹下)下新建一个文件夹.

将目录命名为: MyValidators

然后创建文件: passwordStrength.php

在文件中创建我们的验证方法

class passwordStrength extends CValidator
{
  public $strength;
  private $weak_pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';
  private $strong_pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';
...
}

在类中创建属性,此属性为在验证规则中使用的参数.

CValidator 会自动根据参数来填充这些属性.

我们也创建了两个其他的属性,它们为 preg_match 函数使用的正则表达式.

现在我们应该重写父类的抽象方法(abstract method) validateAttribute

/**
 * Validates the attribute of the object.
 * If there is any error, the error message is added to the object.
 * @param CModel $object the object being validated
 * @param string $attribute the attribute being validated
 */
protected function validateAttribute($object,$attribute)
{
  // check the strength parameter used in the validation rule of our model
  if ($this->strength == 'weak')
   $pattern = $this->weak_pattern;
  elseif ($this->strength == 'strong')
   $pattern = $this->strong_pattern;
  // extract the attribute value from it's model object
  $value=$object->$attribute;
  if(!preg_match($pattern, $value))
  {
    $this->addError($object,$attribute,'your password is too weak!');
  }
}

上面的方法我认为就不用解释了.当然你也可以在 if 的条件中使用常量,我推荐使用.

PHP 相关文章推荐
教你IIS6的PHP最佳配置方法
Sep 05 PHP
php 上传功能实例代码
Apr 13 PHP
通达OA公共代码 php常用检测函数
Dec 14 PHP
php 获取页面中指定内容的实现类
Jan 23 PHP
在WordPress中实现发送http请求的相关函数解析
Dec 29 PHP
功能强大的php分页函数
Jul 20 PHP
浅谈PHP面向对象之访问者模式+组合模式
May 22 PHP
Ajax+PHP实现的分类列表框功能示例
Feb 11 PHP
PHP错误提示It is not safe to rely on the system……的解决方法
Mar 25 PHP
TP5.0框架实现无限极回复功能的方法分析
May 04 PHP
php实现断点续传大文件示例代码
Jun 19 PHP
PHP数组Key强制类型转换实现原理解析
Sep 01 PHP
PHP Yii框架之表单验证规则大全
Nov 16 #PHP
Yii2.0高级框架数据库增删改查的一些操作
Nov 16 #PHP
yii添删改查实例
Nov 16 #PHP
PHP的运行机制与原理(底层)
Nov 16 #PHP
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
Nov 15 #PHP
php经典算法集锦
Nov 14 #PHP
PHP常用的小程序代码段
Nov 14 #PHP
You might like
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
这东西价格,可以买几台TECSUN S-2000
2021/03/02 无线电
PHP开发文件系统实例讲解
2006/10/09 PHP
PHP MemCached高级缓存配置图文教程
2010/08/05 PHP
PHP多线程类及用法实例
2014/12/03 PHP
CI框架中cookie的操作方法分析
2014/12/12 PHP
win7系统配置php+Apache+mysql环境的方法
2015/08/21 PHP
Jquery焦点与失去焦点示例应用
2014/06/10 Javascript
js控制再次点击按钮之间的间隔时间可防止重复提交
2014/08/01 Javascript
Javascript window对象详解
2014/11/12 Javascript
jQuery EasyUi实战教程之布局篇
2016/01/26 Javascript
使用JavaScript实现弹出层效果的简单实例
2016/05/31 Javascript
Bootstrap按钮功能之查询按钮和重置按钮
2016/10/26 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
Node.js常用工具之util模块
2017/03/09 Javascript
AngularJS实现的简单拖拽功能示例
2018/01/02 Javascript
基于JavaScript实现简单的音频播放功能
2018/01/07 Javascript
对vue 键盘回车事件的实例讲解
2018/08/25 Javascript
js作用域和作用域链及预解析
2019/04/11 Javascript
JavaScript函数IIFE使用详解
2019/10/21 Javascript
[08:04]TI4西雅图DOTA2前线报道 海涛探访各路人马
2014/07/09 DOTA
python中使用smtplib和email模块发送邮件实例
2014/04/22 Python
Python实现Youku视频批量下载功能
2017/03/14 Python
使用C++扩展Python的功能详解
2018/01/12 Python
PyQt5每天必学之事件与信号
2018/04/20 Python
python样条插值的实现代码
2018/12/17 Python
Python如何处理大数据?3个技巧效率提升攻略(推荐)
2019/04/15 Python
python mongo 向数据中的数组类型新增数据操作
2020/12/05 Python
全网最详细的PyCharm+Anaconda的安装过程图解
2021/01/25 Python
数学专业毕业生自荐信
2013/11/10 职场文书
初中科学教学反思
2014/01/21 职场文书
2014年国庆节演讲稿
2014/09/19 职场文书
2014年人大工作总结
2014/12/10 职场文书
打架检讨书
2015/01/27 职场文书
2016年师德师风学习心得体会
2016/01/12 职场文书
小数乘法教学反思
2016/02/22 职场文书