Yii2: How to set default attribute values in ActiveRecord?

折月煮酒 提交于 2019-12-03 11:23:06

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() {
        ...
    }
}

The benefits of this approach are

  • You can easily cater for different validation, set up and display cases without resorting to a bunch of ifs and switches
  • You can still keep common code in the parent class to avoid repetition
  • You can make changes to each subclass without worrying about how it will affect the other
  • The individual classes don't need to know about the existence of any of their siblings/children to function correctly

In fact, in our most recent project, we are using search models that don't extend from the related ActiveRecord at all

There's two ways to do this.

$model => new Model();

Now $model has all the default attributes from the database table.

Or in your rules you can use:

[['field_name'], 'default', 'value'=> $defaultValue],

Now $model will always be created with the default values you specified.

You can see a full list of core validators here http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html

Stefano Mtangoo

I know it is answered but I will add my approach. I have Application and ApplicationSearch models. In Application model I add init with a check of the current instance. If its ApplicationSearch I skip initializations.

    public function init()
    { 
        if(!$this instanceof ApplicationSearch)  
        {
            $this->id = hash('sha256',  123);
        }

        parent::init();
    }

also as @mae commented below you can check for existence of search method in current instance, assuming you didn't add any method with name search to the non-search base model so the code becomes:

    public function init()
    { 
        // no search method is available in Gii generated Non search class
        if(!method_exists($this,'search'))  
        {
            $this->id = hash('sha256',  123);
        }

        parent::init();
    }

I've read your question several times and I think there are some contradictions.
You want the defaults to be readable before and during validation and then you try init() or beforeSave(). So, assuming you just want to set the default values in the model so they can be present during the part of the life cycle as long as possible and not interfere with the derived classes, simply set them after initialising the object.

You can prepare separate method where all defaults are set and call it explicitly.

$model = new Model;
$model->setDefaultValues();

Or you can create static method to create model with all default values set and return the instance of it.

$model = Model::createNew();

Or you can pass default values to constructor.

$model = new Model([
    'attribute1' => 'value1',
    'attribute2' => 'value2',
]);

This is not much different from setting the attributes directly.

$model = new Model;
$model->attribute1 = 'value1';
$model->attribute2 = 'value2';

Everything depends on how much transparent would you like your model be to your controller.

This way attributes are set for the whole life cycle except the direct initialisation and it's not interfering with derived search model.

Just override __construct() method in your model like this:

class MyModel extends \yii\db\ActiveRecord {

    function __construct(array $config = [])
       {
           parent::__construct($config);
           $this->attr = 'defaultValue';
       }
    ...
}

You can prepare separate method where all defaults are set and call it explicitly.

$model = new Model;
if($model->isNewRecord())
    $model->setDefaultValues();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!