Это может показаться тривиальным вопросом, однако все очевидные решения, которые я могу придумать, имеют свои недостатки.
Мы хотим иметь возможность устанавливать любое значение атрибута ActiveRecord по умолчанию только для новых записей таким образом, чтобы оно было читаемым до и во время проверки и не мешало производным классам, используемым для поиска.
Значения по умолчанию должны быть установлены и готовы, как только мы создадим экземпляр класса, чтобы (new MyModel)->attr
возвращало значение по умолчанию attr
.
Вот некоторые из возможностей и проблем, которые у них есть:
A) В
MyModel
переопределите методinit()
и назначьте значение по умолчанию, когдаisNewRecord
истинно, например:public function init() { if ($this->isNewRecord) { $this->attr = 'defaultValue'; } parent::init(); }
Проблема: поиск. Если мы явно не отключим наш атрибут по умолчанию в
MySearchModel
(очень подверженный ошибкам, потому что его слишком легко забыть), это также установит значение перед вызовомsearch()
в производном классеMySearchModel
и помешает поиску (атрибутattr
уже будет установлен, поэтому поиск будет возвращать неверные результаты). В Yii1.1 это было решено вызовомunsetAttributes()
перед вызовомsearch()
, однако такого метода нет в Yii2.B) В
MyModel
переопределитеbeforeSave()
следующим образом:public function beforeSave($insert) { if ($insert) { $this->attr = 'defaultValue'; } return parent::beforeSave(); }
Проблема: атрибут не установлен в несохраненных записях.
(new MyModel)->attr
этоnull
. Что еще хуже, даже другие правила проверки, которые полагаются на это значение, не смогут получить к нему доступ, потому чтоbeforeSave()
вызывается после проверки.C) Чтобы убедиться, что значение доступно во время проверки, мы можем вместо этого переопределить
beforeValidate()
и установите там значения по умолчанию следующим образом:public function beforeValidate() { if ($this->isNewRecord) { $this->attr = 'defaultValue'; } return parent::beforeValidate(); }
Проблема: атрибут по-прежнему не установлен в несохраненных (непроверенных) записях. Нам нужно как минимум вызвать
$model->validate()
, если мы хотим получить значение по умолчанию.D) Используйте
DefaultValidator
вrules()
чтобы установить значение атрибута по умолчанию во время проверки следующим образом:public function rules() { return [ [ 'attr', 'default', 'value' => 'defaultValue', 'on' => 'insert', // instantiate model with this scenario ], // ... ]; }
Проблема: То же, что и B) и C). Значение не устанавливается до тех пор, пока мы не сохраним или не проверим запись.
Так как же является правильным способом установить значения атрибутов по умолчанию? Есть ли другой способ без очерченных проблем?
required
! После этого модель будет содержать значения по умолчанию перед вызовами проверки/сохранения. - person Pavel Sokolov   schedule 11.05.2019