Yii2 modelyii ruless里面自定义规则无效,怎么解决

yii 自定义验证规则_懒人程序
支付宝赞助帐号:
yii 自定义验证规则
yii 自定义验证规则
很多时候 yii 提供的验证规则不符合我们的要求,所有我们需要自己定义符合自己的规则.
简单的方法:在 model 内部定义规则
最简单的定义验证规则的方法是在使用它的模型(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 数组中.
你会发现在方法中我们使用了&.
添加错误接受两个参数:第一个参数是在表单中显示错误的属性名,第二个参数时显示的错误信息 。
完整的方法:继承 CValidator 类
如果你想把规则使用在多个模型(model)中,最好的方法时继承 CValidator 类。
继承这个类你可以使用像&&(Yii 1.1.7 版本后可用) 类似的其他功能。
创建类文件
首先要做的是创建类文件.最好的方法时类的文件名和类名相同,可以使用 yii 的延迟加载(lazy loading)功能。
让我们在应用(application)的扩展(extensiions)目录(在 protected 文件夹下)下新建一个文件夹.
将目录命名为:&MyValidators
然后创建文件:&passwordStrength.php
在文件中创建我们的验证方法
class passwordStrength extends CValidator
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)&
* 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_
elseif ($this-&strength == 'strong')
$pattern = $this-&strong_
// extract the attribute value from it's model object
$value=$object-&$
if(!preg_match($pattern, $value))
$this-&addError($object,$attribute,'your password is too weak!');
上面的方法我认为就不用解释了. 当然你也可以在 if 的条件中使用常量,我推荐使用.
实现客户端验证
如果要实现客户端验证还需要重写类中的方法&.
* Returns the JavaScript needed for performing client-side validation.
* @param CModel $object the data object being validated
* @param string $attribute the name of the attribute to be validated.
* @return string the client-side validation script.
* @see CActiveForm::enableClientValidation
public function clientValidateAttribute($object,$attribute)
// check the strength parameter used in the validation rule of our model
if ($this-&strength == 'weak')
$pattern = $this-&weak_
elseif ($this-&strength == 'strong')
$pattern = $this-&strong_
$condition=&!value.match({$pattern})&;
if(&.$condition.&) {
messages.push(&.CJSON::encode('your password is too weak, you fool!').&);
正如你看到的此方法简单的返回了一个在验证中将使用到的 javascript.
最后一步:在模块(model)中怎么使用自定义的验证类
下面有几种方法来实现:
你可以在返回 规则数组(ruels array)前 使用&&方法,或使用Yii的符号方式:
* @return array validation rules for model attributes.
public function rules()
return array(
array('password', 'ext.MyValidators.passwordStrength', 'strength'=&self::STRONG),
支持键盘 ← →Posts - 198,
Articles - 0,
Comments - 1094
贵有恒,何必三更起五更勤;最无益,只怕一日曝十日寒
08:00 by JustRun, ... 阅读,
Asp.net MVC中的提供非常简单易用的数据验证解决方案. 通过<ponentModel.DataAnnotations提供的很多的验证规则(Required, StringLength等)。但是常常有这样的需求,我们希望能够把model的验证规则,保存到数据或者xml文件中,而不是代码里, 这样的好处是,我们可以很方便的修改验证规则和错误消息,避免需要重新发布网站。
这篇文章,一起来看看是如何通过自定义ModelValidatorProvider来通过XML文件配置对于Model的验证。
一、简单回顾内置MVC验证的使用
二、分析MVC验证的内部过程
三、一个例子,针对ContactInfo的验证
四、具体实现和应用XmlModelValidatorProvider
一,简单回顾内置MVC验证的使用
下面是典型的MVC验证规则的代码和页面展示效果。
二,分析MVC验证的内部过程
1. 实际做验证的是ModelValidator
当我们如上图,在为Person类添加了各种验证规则的dataannotation attributes后,实际操刀来做验证的是DataAnnotationsModelValidator类.DataAnnotationsModelValidator继承自抽象类ModelValidator,实现了抽象方法Validate, 在该方法中根据Person类中定义的验证规则,对于所有Person的实例进行验证,同时返回一个ModelValidationResult的集合。
2. ModelValidator是由ModelValidatorProviders提供的
MVC在验证过程中使用到的ModelValidator又是由ModelValidatorProviders类提供的, ModelValidatorProviders是一个抽象类,有个抽象方法GetValidators.
该类的定义是这样的
namespace System.Web.Mvc
public abstract class ModelValidatorProvider
public abstract IEnumerable&ModelValidator& GetValidators(ModelMetadata metadata, ControllerContext context);
实际运行中,MVC使用的是继承于ModelValidatorProvider, 实现了GetValidators方法的DataAnnotationsModelValidatorProvider类.
3. MVC的验证过程中可以存在多个ModelValidatorProvider
MVC中可以多个ModelValidatorProvider同时起作用, 他们的效果可以叠加。我们可以使用默认的根据Attribute来定义验证规则的DataAnnotationsModelValidatorProvider,也还可以同时使用我们下面的XmlModelValidatorProvider从xml文件中获取验证规则来做验证。
三,一个例子,针对ContactInfo的验证
下面这个ContactInfo类是我们用来做实际验证的,包含了一些常用的典型的验证,Required, Email, Url等
public class ContactInfo
public string FirstName { get; set; }
public string LastName{get;set;}
public string Email{get;set;}
public string Url{get;set;}
下面的这个xml文件,定义的是关于ContactInfo类的验证规则,以前我们是写在ContactInfo类中的,现在把它分离出来,放到Content\Validation\Rules\ContactInfo.xml文件中.
这里的message中的值只是一个message的key, message的具体内容放在另外一个xml文件中。
&?xml version="1.0" encoding="utf-8" ?&
&validator property="FirstName" type="Required"
message="FirstName_Required" /&
&validator property="FirstName" type="StringLength" arg-int="50" message="FirstName_Length" /&
&validator property="LastName" type="Required"
message="LastName_Required" /&
&validator property="LastName" type="StringLength" arg-int="255" message="LastName_Length" /&
&validator property="Email" type="Required"
message="Email_Required" /&
&validator property="Email" type="StringLength" arg-int="255" message="Email_Length" /&
&validator property="Email" type="RegularExpression" arg="^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$" message="Email_RegularExpression" /&
&validator property="Url" type="StringLength" arg-int="255" message="Url_Length" /&
&validator property="Url" type="RegularExpression" arg="(http://)?(www\.)?\w+\.(com|net|edu|org)" message="Url_RegularExpression" /&
存放message的是Content\Validation\Messages\ContactInfo.xml文件
&?xml version="1.0" encoding="utf-8" ?&
&messages&
&!-- filed error message --&
&message key="FirstName_Required" text="The Frist Name field is required."&&/message&
&message key="FirstName_Length" text="The field maximum length is 50"&&/message&
&message key="LastName_Required" text="The Last Name field is required."&&/message&
&message key="LastName_Length" text="The field maximum length is 255"&&/message&
&message key="Email_Required" text="The Email field is required."&&/message&
&message key="Email_Length" text="The field maximum length is 255"&&/message&
&message key="Email_RegularExpression" text="Invalid email."&&/message&
&message key="Url_Length" text="The field maximum length is 255"&&/message&
&message key="Url_RegularExpression" text="Invalid URL."&&/message&
&/messages&
四,具体实现和应用XmlModelValidatorProvider
下面是我们最重要的XmlModelValidatorProvider的实现代码
public class XmlModelValidatorProvider : ModelValidatorProvider
// 用来保存ponentModel.DataAnnotations中已经存在的验证规则,也就是MVC自带的Required等验证规则, 因为我们只是验证规则的"源"不一样,一个是代码中,一个是xml,但是验证过程是一样的,所以要重用MVC中的已经写好的验证。
private readonly Dictionary&string, Type& _validatorT
private readonly string _xmlFolderPath = HttpContext.Current.Server.MapPath("~//Content//Validation//Rules");
public XmlModelValidatorProvider()
_validatorTypes = Assembly.Load("ponentModel.DataAnnotations").GetTypes()
.Where(t =& t.IsSubclassOf(typeof (ValidationAttribute)))
.ToDictionary(t =& t.Name, t =& t);
#region Stolen from DataAnnotationsModelValidatorProvider
// delegate that converts ValidationAttribute into DataAnnotationsModelValidator
internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory =
(metadata, context, attribute) =& new DataAnnotationsModelValidator(metadata, context, attribute);
internal static Dictionary&Type, DataAnnotationsModelValidationFactory& AttributeFactories = new Dictionary
&Type, DataAnnotationsModelValidationFactory&
typeof (RangeAttribute),
( metadata, context, attribute)
new RangeAttributeAdapter (metadata, context, ( RangeAttribute ) attribute)
typeof (RegularExpressionAttribute),
( metadata, context, attribute)
new RegularExpressionAttributeAdapter (metadata, context, ( RegularExpressionAttribute ) attribute)
typeof (RequiredAttribute),
( metadata, context, attribute) =&
new RequiredAttributeAdapter (metadata, context, ( RequiredAttribute ) attribute)
typeof (StringLengthAttribute),
( metadata, context, attribute) =&
new StringLengthAttributeAdapter (metadata, context, ( StringLengthAttribute ) attribute)
#endregion
// 重写GetValidators方法,该从xml文件中获取。根据xml的配置,返回对应的Validator集合
public override IEnumerable&ModelValidator& GetValidators(ModelMetadata metadata, ControllerContext context)
var results = new List&ModelValidator&();
// whether the validation is for a property or model
// (remember we can apply validation attributes to a property or model and same applies here as well)
var isPropertyValidation = metadata.ContainerType != null && !String.IsNullOrEmpty(metadata.PropertyName);
var rulesPath = String.Format("{0}\\{1}.xml", _xmlFolderPath,
isPropertyValidation ? metadata.ContainerType.Name : metadata.ModelType.Name);
var rules = File.Exists(rulesPath)
? XElement.Load(rulesPath).XPathSelectElements(String.Format(
"./validator[@property='{0}']",
isPropertyValidation ? metadata.PropertyName : metadata.ModelType.Name)).ToList()
: new List&XElement&();
// Produce a validator for each validation attribute we find
foreach (var rule in rules)
DataAnnotationsModelValidationF
var validatorType = _validatorTypes[String.Concat(rule.Attribute("type").Value, "Attribute")];
if (!AttributeFactories.TryGetValue(validatorType, out factory))
factory = DefaultAttributeF
var validator = (ValidationAttribute) Activator.CreateInstance(validatorType, GetValidationArgs(rule));
validator.ErrorMessage = rule.Attribute("message") != null &&
!String.IsNullOrEmpty(rule.Attribute("message").Value)
? GetValidationMessage(isPropertyValidation ? metadata.ContainerType.Name : metadata.ModelType.Name, rule.Attribute("message").Value)
results.Add(factory(metadata, context, validator));
private string GetValidationMessage(string model, string key)
return MessageProvider.GetViewModelValidationMessage(model, key);
// read the arguments passed to the validation attribute and cast it their respective type.
private object[] GetValidationArgs(XElement rule)
var validatorArgs = rule.Attributes().Where(a =& a.Name.ToString().StartsWith("arg"));
var args = new object[validatorArgs.Count()];
var i = 0;
foreach (var arg in validatorArgs)
var argName = arg.Name.ToString();
var argValue = arg.V
if (!argName.Contains("-"))
args[i] = argV
var argType = argName.Split('-')[1];
switch (argType)
case "int":
args[i] = int.Parse(argValue);
case "datetime":
args[i] = DateTime.Parse(argValue);
case "char":
args[i] = Char.Parse(argValue);
case "double":
args[i] = Double.Parse(argValue);
case "decimal":
args[i] = Decimal.Parse(argValue);
case "bool":
args[i] = Boolean.Parse(argValue);
args[i] = argV
&最后,在Global.cs文件中,把XmlModelValidatorProvider添加到MVC的ModelValidatorProvidersCollection中
ModelValidatorProviders.Providers.Add(new XmlModelValidatorProvider());

我要回帖

更多关于 yii model rules 的文章

 

随机推荐