扩展Yii2的核心验证类 [ 2.0 版本 ]
Yii2的Validator是非常好用的一类方法,它辅助Model层,完成对数据的校验。现在核心的验证器有这么几类:
[[BooleanValidator]] - 要求属性必须为Bool类型
[[CompareValidator]] - 完成两个属性的比较
[[DateValidator]] - 要求属性必须为日期类型
[[EachValidator]] - 要求数组的每个元素必须满足某个条件
[[EmailValidator]] - 要求属性必须为邮件格式
[[ExistValidator]] - 要求该属性必须存在于此模型或者别的模型个某个属性当中
[[StringValidator]] - 要求该属性必须为字符串
[[RangeValidator]] - 要求属性必须在某个范围之内取值
.....
使用起来,它们都有一样的面孔,那就是,在复写的model::rules方法里面增加一条规则:
['country', 'in', 'range' => ['china', 'usa'], 'message' => 'the country is wrong']
这条规则就可以保证country这个属性必须在china和usa之间二选一,否则就会报'the country is wrong'错误。是不是非常的简单?
这个家族的验证器在活动记录ActiveRecord的使用时非常有用,能保证你插入数据库的数据是正确无误的。
已有的校验类虽然很丰富,但是毕竟不能满足我们全部的对数据校验需求,我们希望能扩展已有的验证器。有没有这样一个方法,既能能以这样简单的方式使用,又能方便我们自己定义校验规则?这就是今天要跟大家分享的内容。
直接上代码:
class RegexValidator extends Validator
{
/**
* @var string|array 所要采用的验证方法,可以为string,也可以为如果个方法组成的array
* 所有的方法必须属于RegexValidator
*/
public $method = null;
/**
* @var array 验证的方法列表
* 方法必须属于RegexValidator
*/
private $_methodArray = [];
/**
* @inheritdoc
*/
public function init()
{
parent::init();
$this->_methodArray = (array)$this->method;
if(empty($this->_methodArray)){
throw new InvalidConfigException("Configuration error:no validating method are found!");
}
foreach($this->_methodArray as $method){
if(!$this->hasMethod($method)){
throw new InvalidConfigException("Validating method:\"{$method}\" does not exits!");
}
}
}
/**
* @inheritdoc
*/
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
//将错误信息转化为数组,数组元素对应[_methodArray]的验证方法
$this->message = (array)$this->message;
foreach($this->_methodArray as $k => $method){
$ret = call_user_func([$this, $method], $value);
if($ret === false){
$error = isset($this->message[$k]) ? $this->message[$k] : Yii::t('yii', '{attribute} is invalid.');
$this->addError($model, $attribute, $error);
}
}
}
/**
* @inheritdoc
*/
protected function validateValue($value)
{
$this->message = (array)$this->message;
foreach($this->_methodArray as $k => $method){
$ret = call_user_func([$this, $method], $value);
if($ret === false){
$error = isset($this->message[$k]) ? $this->message[$k] : Yii::t('yii', "\"{$value}\" is invalid specified by the validator:". static::className() ."::$method");
return [$error, []];
}
}
return null;
}
/**
* @inheritdoc
*/
public function clientValidateAttribute($model, $attribute, $view)
{
}
//...这里是你的逻辑……
/**
* 由26个大写英文字母组成的字符串
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function uperchars($data = null)
{
$_pattern = "/^[A-Z]+$/";
return self::_regex($_pattern, $data);
}
/**
* 由26个小写写英文字母组成的字符串
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function lowerchars($data = null)
{
$_pattern = "/^[a-z]+$/";
return self::_regex($_pattern, $data);
}
/**
* 由数字和26个英文字母组成的字符串
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function numschars($data = null)
{
$_pattern = "/^[A-Za-z0-9]+$/";
return self::_regex($_pattern, $data);
}
/**
* 手机号码
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function mobile($data = null)
{
$_pattern = "/^(0|86|17951)?(13[0-9]|15[012356789]|1[78][0-9]|14[57])[0-9]{8}$/";
return self::_regex($_pattern, $data);
}
/**
* Email
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function email($data = null)
{
$_res = filter_var($data, FILTER_VALIDATE_EMAIL);
return empty($_res) ? false : true;
}
/**
* 邮编
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function postcode($data = null)
{
$_pattern = "/^[1-9]\d{5}(?!\d)$/";
return self::_regex($_pattern, $data);
}
/**
* 中文
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function zh($data = null)
{
$_pattern = "/^[\x{4e00}-\x{9fa5}]+$/u";
return self::_regex($_pattern, $data);
}
/**
* URL地址
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function url($data = null)
{
$_res = filter_var($data, FILTER_VALIDATE_URL);
return empty($_res) ? false : true;
}
/**
* 身份证
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function identity($data = null)
{
$_pattern = "/^(^\d{15}$)|(^\d{17}([0-9]|X)$)$/";
return self::_regex($_pattern, $data);
}
/**
* IPv4
* @param $data mixed 数字或者字符串
* @return bool
**/
public static function ip($data = null)
{
$_res = filter_var($data, FILTER_VALIDATE_IP);
return empty($_res) ? false : true;
}
/**
* 匹配正则公共方法
* @param $pattern string 匹配模式
* @param $subject string 对象
* @return bool
*/
private static function _regex($pattern, $subject = null)
{
if ($subject === null)
{
return false;
}
if (preg_match($pattern, $subject))
{
return true;
}
return false;
}
}
首先,必须继承yii\validators\Validator
,并且复写validateAttribute
和validateValue
方法。validateAttribute
是验证属性用的,调用$module->validate()
时会对其隐式的调用;validateValue
则可以不依赖Model独立使用。clientValidateAttribute
则是在客户端实现数据校验的部分(这部分等待聪明的你去DIY)。init实现初始化的功能。
复写了基础的几个Validator方法,然后就是我们自己的校验数据的逻辑:
[[zh]] - 校验数据是否为中文
[[postcode]] - 校验数据是否为邮编
[[mobile]] - 校验数据是否为手机号码
……
接下来,当然是最精彩的部分——如何使用?有三种方式可以方便您调用:
1.用在数据模型model的rules方法里面:
['name', RegexValidator::className(), 'method' => 'lowerchars', 'message' => '名字必须全为小写字母']
[
['mobile', 'status'],
RegexValidator::className(),
'method' => ['mobile', 'zh'],
'message' => ['手机格式不正确', '必须为中文']
]
这里需要在Model里引入RegexValidator类,并用RegexValidator::className()代替核心验证器'in','string','exsit'等;
规则里的'method'是你自己定义的(静态)方法,你的校验逻辑之所在。可以单个引用,也可以为数组,当为数组时对应的错误信息'message'也得为数组,而且错误信息与之对应。
当调用$model->validate(),如果不满足以上的条件这个方法就会返回false,而且在$model->getErrors()里面会返回具体的错误信息:
[
'name' => [
'名字必须全为小写字母',
],
'mobile' => [
'手机格式不正确',
],
'zh' => [
'必须为中文',
],
]
返回的错误信息和核心验证器格式是完全一样的。
2.脱离model独立使用,必须要配置[method]参数:
$valid = new RegexValidator([
'method' => ['zh', 'negative'],
'message' => ['必须为中文', '必须为负数'],
)];
$valid->validate($value, $error);
if($error){
echo $error;
}
同样的和核心验证器的使用方法相同;
3.直接调用RegexValidator里的各个静态方法进行验证
$value = 'Abc';
$ret = RegexValidator::mobile($value);
if(!$ret){
echo ...;
}
这是最简单调用方法,此时无法使用错误提示。
这个类是可以扩展的,您可以将自己的逻辑在[[number]]以降继续添加。
此文为抛砖引入之作,欢迎大家继续在拙作上继续添砖加瓦,使得Yii2数组验证器的功能更加强大!
米粒人生 苏州
最后登录:2021-04-25
在线时长:47小时54分
- 粉丝111
- 金钱6555
- 威望230
- 积分9325
热门源码
- 基于 Yii 2 + Bootstrap 3 搭建一套后台管理系统 CMF
- 整合完 yii2-rbac+yii2-admin+adminlte 等库的基础开发后台源码
- 适合初学者学习的一款通用的管理后台
- yii-goaop - 将 goaop 集成到 Yii,在 Yii 中优雅的面向切面编程
- yii-log-target - 监控系统异常且多渠道发送异常信息通知
- 店滴云1.3.0
- 面向对象的一小步:添加 ActiveRecord 的 Scope 功能
- Yii2 开源商城 FecShop
- 基于 Yii2 开发的多店铺商城系统,免费开源 + 适合二开
- leadshop - 基于 Yii2 开发的一款免费开源且支持商业使用的商城管理系统
共 5 条评论
前排 分享是大家共同进步的阶梯 献上我的敬意
好的,谢谢!最近在解剖Yii2源代码,以后会分享更多东西!
表示感谢!
一起进步!
谢谢分享。
共同成长!
刚好需要,收藏了,谢谢楼主分享!
文章不错,针对数组的验证yii2本身就一个each而已,但是满足不了大众的需求。那么扩展自己项目的验证需求就非常有必要了。楼主开了个好头。
是的,简单的扩展可以就在我这代码下面继续写;复杂的就重新写一个Validator