yii验证系统学习记录,基于yiicms(二)
1 /** 2 * Validates the specified object. 3 * @param \yii\base\Model $model the data model being validated 4 * @param array|null $attributes the list of attributes to be validated. 5 * Note that if an attribute is not associated with the validator - it will be 6 * ignored. If this parameter is null, every attribute listed in [[attributes]] will be validated. 7 */ 8 public function validateAttributes($model, $attributes = null) 9 { 10 //传入的是被验证的属性。属性很可能是某一具体场景下的需验证属性 11 //这里进行验证器过滤,必须同时在场景中和验证器中都有,才会接着去验证。 12 if (is_array($attributes)) { 13 $newAttributes = []; 14 foreach ($attributes as $attribute) { 15 if (in_array($attribute, $this->getAttributeNames(), true)) { 16 $newAttributes[] = $attribute; 17 } 18 } 19 $attributes = $newAttributes; 20 } else { 21 $attributes = $this->getAttributeNames(); 22 } 23 24 foreach ($attributes as $attribute) { 25 $skip = $this->skipOnError && $model->hasErrors($attribute) 26 || $this->skipOnEmpty && $this->isEmpty($model->$attribute);
//可以肯定的是在一般场景下$skip就是false,因此下面的判断是会执行的,而$this->when是rules里传入的回调,一般没使用这个回调,因此为null,
//继续执行$this->validateAttribute($model, $attribute);
27 if (!$skip) { 28 //此处when默认为null,也即用户在验证规则里没设置。继续下一步 29 if ($this->when === null || call_user_func($this->when, $model, $attribute)) { 30 $this->validateAttribute($model, $attribute); 31 } 32 } 33 } 34 }
这个验证指定对象的验证器在(一)介绍过了,这里贴一下代码。继续执行$this->validateAttribute($model, $attribute);代码如下:
1 /** 2 * Validates a single attribute. 3 * Child classes must implement this method to provide the actual validation logic. 4 * @param \yii\base\Model $model the data model to be validated 5 * @param string $attribute the name of the attribute to be validated. 6 */ 7 public function validateAttribute($model, $attribute) 8 { 9 $result = $this->validateValue($model->$attribute); 10 if (!empty($result)) { 11 $this->addError($model, $attribute, $result[0], $result[1]); 12 } 13 }
验证一个单独属性,子类必须集成这个方法来提供实际的验证逻辑,$model是被验证的model,$attribute是被验证的属性。哦,原来是在这添加的错误,执行完后,validate方法会返回这个错误状态,有错或无错。进这个validateValue方法看一下。
1 /** 2 * Validates a value. 3 * A validator class can implement this method to support data validation out of the context of a data model. 4 * @param mixed $value the data value to be validated. 5 * @return array|null the error message and the parameters to be inserted into the error message. 6 * Null should be returned if the data is valid. 7 * @throws NotSupportedException if the validator does not supporting data validation without a model 8 */ 9 protected function validateValue($value) 10 { 11 throw new NotSupportedException(get_class($this) . ' does not support validateValue().'); 12 }
这个方法是个虚拟方法,不能直接被调用,必须在子类中实现该方法用以支持数据模型上下文的验证。$value是被验证的值,返回的错误信息,参数会插入错误信息,null返回代表数据不可用。如果验证器不支持数据验证模型将抛出错误。
咱们以required验证器为例:
1 <?php 2 /** 3 * @link http://www.yiiframework.com/ 4 * @copyright Copyright (c) 2008 Yii Software LLC 5 * @license http://www.yiiframework.com/license/ 6 */ 7 8 namespace yii\validators; 9 10 use Yii; 11 12 /** 13 * RequiredValidator validates that the specified attribute does not have null or empty value. 14 * 15 * @author Qiang Xue <qiang.xue@gmail.com> 16 * @since 2.0 17 */ 18 class RequiredValidator extends Validator 19 { 20 /** 21 * @var bool whether to skip this validator if the value being validated is empty. 22 */ 23 public $skipOnEmpty = false; 24 /** 25 * @var mixed the desired value that the attribute must have. 26 * If this is null, the validator will validate that the specified attribute is not empty. 27 * If this is set as a value that is not null, the validator will validate that 28 * the attribute has a value that is the same as this property value. 29 * Defaults to null. 30 * @see strict 31 */ 32 public $requiredValue; 33 /** 34 * @var bool whether the comparison between the attribute value and [[requiredValue]] is strict. 35 * When this is true, both the values and types must match. 36 * Defaults to false, meaning only the values need to match. 37 * Note that when [[requiredValue]] is null, if this property is true, the validator will check 38 * if the attribute value is null; If this property is false, the validator will call [[isEmpty]] 39 * to check if the attribute value is empty. 40 */ 41 public $strict = false; 42 /** 43 * @var string the user-defined error message. It may contain the following placeholders which 44 * will be replaced accordingly by the validator: 45 * 46 * - `{attribute}`: the label of the attribute being validated 47 * - `{value}`: the value of the attribute being validated 48 * - `{requiredValue}`: the value of [[requiredValue]] 49 */ 50 public $message; 51 52 53 /** 54 * @inheritdoc 55 */ 56 public function init() 57 { 58 parent::init(); 59 if ($this->message === null) { 60 $this->message = $this->requiredValue === null ? Yii::t('yii', '{attribute} cannot be blank.') 61 : Yii::t('yii', '{attribute} must be "{requiredValue}".'); 62 } 63 } 64 65 /** 66 * @inheritdoc 67 */ 68 protected function validateValue($value) 69 { 70 if ($this->requiredValue === null) { 71 if ($this->strict && $value !== null || !$this->strict && !$this->isEmpty(is_string($value) ? trim($value) : $value)) { 72 return null; 73 } 74 } elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) { 75 return null; 76 } 77 if ($this->requiredValue === null) { 78 return [$this->message, []]; 79 } else { 80 return [$this->message, [ 81 'requiredValue' => $this->requiredValue, 82 ]]; 83 } 84 } 85 86 /** 87 * @inheritdoc 88 */ 89 public function clientValidateAttribute($model, $attribute, $view) 90 { 91 ValidationAsset::register($view); 92 $options = $this->getClientOptions($model, $attribute); 93 94 return 'yii.validation.required(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');'; 95 } 96 97 /** 98 * @inheritdoc 99 */ 100 public function getClientOptions($model, $attribute) 101 { 102 $options = []; 103 if ($this->requiredValue !== null) { 104 $options['message'] = $this->formatMessage($this->message, [ 105 'requiredValue' => $this->requiredValue, 106 ]); 107 $options['requiredValue'] = $this->requiredValue; 108 } else { 109 $options['message'] = $this->message; 110 } 111 if ($this->strict) { 112 $options['strict'] = 1; 113 } 114 115 $options['message'] = $this->formatMessage($options['message'], [ 116 'attribute' => $model->getAttributeLabel($attribute), 117 ]); 118 119 return $options; 120 } 121 }
这个验证器用于验证非空非null属性。$skipOnEmpty,此时这个值设置为false,而不是基类validator上的true,也就是不跳过空值。$requiredValue是属性必须有的期待值,如果为null,验证器将验证指定的属性是否为空。如果不为空,那就验证跟该值指定的属性同名的属性。默认是null。$strict用来指定$requiredValue给定属性值跟传入属性值是否完全相同,如果为真,类型和值必须都相同。默认为假,只检查值,注意当requiredValue为null,如果这个属性为真,验证器将检查属性值是否为null,如果属性为false,验证器就会调用isEmpty检查属性值是否为空。$message是用户定义的错误信息,如果包含下面的占位符将根据规则进行替换。
* - `{attribute}`: the label of the attribute being validated
* - `{value}`: the value of the attribute being validated
* - `{requiredValue}`: the value of [[requiredValue]]
第一个被验证的属性标签,第二个被验证属性值,第三个被验证的requiredValue的值。