Yii2:如何在 ActiveRecord 中设置默认属性值? [英] Yii2: How to set default attribute values in ActiveRecord?
问题描述
这似乎是一个微不足道的问题,但是我能想到的所有显而易见的解决方案都有其自身的缺陷.
This may seem like a trivial question, however all of the obvious solutions that I can think of have their own flaws.
我们想要的是能够仅为新记录设置任何默认的 ActiveRecord 属性值,以使其在验证之前和验证期间可读,并且不会干扰用于搜索的派生类.
What we want is to be able to set any default ActiveRecord attribute value for new records only, in a way that makes it readable before and during validation and does not interfere with derived classes used for search.
需要在我们实例化类后立即设置并准备好默认值,以便 (new MyModel)->attr
返回默认的 attr
值.
The default values need to be set and ready as soon as we instantiate the class, so that (new MyModel)->attr
returns the default attr
value.
以下是一些可能性及其存在的问题:
Here are some of the possibilities and the problems they have:
A) 在
MyModel
覆盖init()
方法并在isNewRecord
时分配默认值确实如此:
A) In
MyModel
override theinit()
method and assign default value whenisNewRecord
is true like so:
public function init() {
if ($this->isNewRecord) {
$this->attr = 'defaultValue';
}
parent::init();
}
问题:搜索.除非我们在 MySearchModel
中明确取消设置我们的默认属性(非常容易出错,因为太容易忘记),否则这也会在调用 search()
之前设置值派生 MySearchModel
类并干扰搜索(attr
属性已被设置,因此搜索将返回不正确的结果).在 Yii1.1 中,这是通过调用 unsetAttributes()
在调用 search()
之前,但是 Yii2 中没有这种方法.
Problem: Search. Unless we explicitly unset our default attribute in MySearchModel
(very error-prone because it is too easy to forget), this will also set the value before calling search()
in the derived MySearchModel
class and interfere with searching (the attr
attribute will already be set so search will be returning incorrect results). In Yii1.1 this was resolved by calling unsetAttributes()
before calling search()
, however no such method exists in Yii2.
B) 在 MyModel
中覆盖 beforeSave()
方法如下:
B) In MyModel
override the beforeSave()
method like so:
public function beforeSave($insert) {
if ($insert) {
$this->attr = 'defaultValue';
}
return parent::beforeSave();
}
问题:未保存的记录中未设置属性.(new MyModel)->attr
是 null
.更糟糕的是,即使是其他依赖此值的验证规则也无法访问它,因为 beforeSave()
被调用 after 验证.
Problem: Attribute is not set in unsaved records. (new MyModel)->attr
is null
. Worse yet, even other validation rules that rely on this value will not be able to access it, because beforeSave()
is called after validation.
C) 为确保在验证期间该值可用,我们可以改写 beforeValidate()
方法并像这样设置默认值:
C) To ensure the value is available during validation we can instead override the beforeValidate()
method and set the default values there like so:
public function beforeValidate() {
if ($this->isNewRecord) {
$this->attr = 'defaultValue';
}
return parent::beforeValidate();
}
问题:在未保存(未验证)的记录中仍未设置属性.如果我们想获得默认值,我们至少需要调用 $model->validate()
.
Problem: Attribute is still not set in unsaved (unvalidated) records. We need to at least call $model->validate()
if we want to get the default value.
D) 使用 <rules()
中的 code>DefaultValidator 用于在验证期间设置默认属性值,如下所示:
D) Use DefaultValidator
in rules()
to set a default attribute value during validation like so:
public function rules() {
return [
[
'attr', 'default',
'value' => 'defaultValue',
'on' => 'insert', // instantiate model with this scenario
],
// ...
];
}
问题:与 B) 和 C) 相同.在我们实际保存或验证记录之前,不会设置值.
Problem: Same as B) and C). Value is not set until we actually save or validate the record.
那么设置默认属性值的正确方法是什么?没有列出的问题还有其他方法吗?
So what is the right way to set default attribute values? Is there any other way without the outlined problems?
推荐答案
这是 Yii 臃肿的多用途 ActiveRecords 的问题
This is a hangup with Yii's bloated multi-purpose ActiveRecords
在我看来,表单模型、活动记录和搜索模型最好拆分成单独的类/子类
In my humble opinion the form models, active records, and search models would be better off split into separate classes/subclasses
为什么不拆分搜索模型和表单模型?
Why not split your search models and form models?
abstract class Creature extends ActiveRecord {
...
}
class CreatureForm extends Creature {
public function init() {
parent::init();
if ($this->isNewRecord) {
$this->number_of_legs = 4;
}
}
}
class CreatureSearch extends Creature {
public function search() {
...
}
}
这种方法的好处是
- 您可以轻松应对不同的验证、设置和显示案例,而无需求助于一堆 if 和开关
- 您仍然可以在父类中保留通用代码以避免重复
- 您可以对每个子类进行更改,而不必担心会如何影响其他子类
- 各个类不需要知道其任何兄弟姐妹/孩子的存在即可正常运行
事实上,在我们最近的项目中,我们使用的搜索模型根本不从相关的 ActiveRecord 扩展
In fact, in our most recent project, we are using search models that don't extend from the related ActiveRecord at all
这篇关于Yii2:如何在 ActiveRecord 中设置默认属性值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!