EachValidator.php
4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\validators;
use yii\base\InvalidConfigException;
use Yii;
use yii\base\Model;
/**
* EachValidator validates an array by checking each of its elements against an embedded validation rule.
*
* ~~~php
* class MyModel extends Model
* {
* public $categoryIDs = [];
*
* public function rules()
* {
* return [
* // checks if every category ID is an integer
* ['categoryIDs', 'each', 'rule' => ['integer']],
* ]
* }
* }
* ~~~
*
* > Note: This validator will not work with inline validation rules in case of usage outside the model scope,
* e.g. via [[validate()]] method.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.4
*/
class EachValidator extends Validator
{
/**
* @var array|Validator definition of the validation rule, which should be used on array values.
* It should be specified in the same format as at [[yii\base\Model::rules()]], except it should not
* contain attribute list as the first element.
* For example:
*
* ~~~
* ['integer']
* ['match', 'pattern' => '/[a-z]/is']
* ~~~
*
* Please refer to [[yii\base\Model::rules()]] for more details.
*/
public $rule;
/**
* @var boolean whether to use error message composed by validator declared via [[rule]] if its validation fails.
* If enabled, error message specified for this validator itself will appear only if attribute value is not an array.
* If disabled, own error message value will be used always.
*/
public $allowMessageFromRule = true;
/**
* @var Validator validator instance.
*/
private $_validator;
/**
* @inheritdoc
*/
public function init()
{
parent::init();
if ($this->message === null) {
$this->message = Yii::t('yii', '{attribute} is invalid.');
}
}
/**
* Returns the validator declared in [[rule]].
* @param Model|null $model model in which context validator should be created.
* @return Validator the declared validator.
*/
private function getValidator($model = null)
{
if ($this->_validator === null) {
$this->_validator = $this->createEmbeddedValidator($model);
}
return $this->_validator;
}
/**
* Creates validator object based on the validation rule specified in [[rule]].
* @param Model|null $model model in which context validator should be created.
* @throws \yii\base\InvalidConfigException
* @return Validator validator instance
*/
private function createEmbeddedValidator($model)
{
$rule = $this->rule;
if ($rule instanceof Validator) {
return $rule;
} elseif (is_array($rule) && isset($rule[0])) { // validator type
if (!is_object($model)) {
$model = new Model(); // mock up context model
}
return Validator::createValidator($rule[0], $model, $this->attributes, array_slice($rule, 1));
} else {
throw new InvalidConfigException('Invalid validation rule: a rule must be an array specifying validator type.');
}
}
/**
* @inheritdoc
*/
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
$validator = $this->getValidator();
if ($validator instanceof FilterValidator && is_array($value)) {
$filteredValue = [];
foreach ($value as $k => $v) {
if (!$validator->skipOnArray || !is_array($v)) {
$filteredValue[$k] = call_user_func($validator->filter, $v);
}
}
$model->$attribute = $filteredValue;
} else {
$this->getValidator($model); // ensure model context while validator creation
parent::validateAttribute($model, $attribute);
}
}
/**
* @inheritdoc
*/
protected function validateValue($value)
{
if (!is_array($value)) {
return [$this->message, []];
}
$validator = $this->getValidator();
foreach ($value as $v) {
$result = $validator->validateValue($v);
if ($result !== null) {
return $this->allowMessageFromRule ? $result : [$this->message, []];
}
}
return null;
}
}