If you take a look at yii\validators\EachValidator source, when
attribute from validator inside rule
never got called:
if (!$validator->skipOnEmpty || !$validator->isEmpty($v)) {
$validator->validateAttribute($model, $attribute);
}
Compare that to its parent class yii\validators\Validator, it has this:
foreach ($attributes as $attribute) {
$skip = $this->skipOnError && $model->hasErrors($attribute)
|| $this->skipOnEmpty && $this->isEmpty($model->$attribute);
if (!$skip) {
if ($this->when === null || call_user_func($this->when, $model, $attribute)) {
$this->validateAttribute($model, $attribute);
}
}
}
One way to achieve your goal is to extend yii\validators\EachValidator
and override its validateAttribute($model, $attribute)
method (as well as private property and methods defined there):
/**
* @var Validator validator instance.
*/
private $_validator;
/**
* 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)
{
// same as in parent
}
/**
* 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)
{
// same as in parent
}
/**
* {@inheritdoc}
*/
public function validateAttribute($model, $attribute)
{
... // same as in parent
foreach ($value as $k => $v) {
$model->clearErrors($attribute);
$model->$attribute = $v;
// start override original code
$skip = $validator->skipOnEmpty && $validator->isEmpty($v);
if (!$skip) {
if ($validator->when === null || call_user_func($validator->when, $model, $attribute)) {
$validator->validateAttribute($model, $attribute);
}
}
// end override original code
$filteredValue[$k] = $model->$attribute;
if ($model->hasErrors($attribute)) {
... // same as in parent
}
}
... // same as in parent
}
Use your custom class in your rules()
like this:
[['list'], \app\models\EachValidator::className(), 'rule' => ['required', 'when' => function ($model) {return false;}]]