Yii2:如何在 ActiveRecord 中设置默认属性值? [英] Yii2: How to set default attribute values in ActiveRecord?

查看:20
本文介绍了Yii2:如何在 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 the init() method and assign default value when isNewRecord 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)->attrnull.更糟糕的是,即使是其他依赖此值的验证规则也无法访问它,因为 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆