Best practices on define a value to a model attribute

Hi, everyone!

This is my very first interaction in the forum and before anything else I’d like to congratulate everyone involved in this amazing tool! It’s quite amazing how powerful it can get.

Last week I had the chance to start a new personal project and I faced a doubt setting a fixed value in attributes for my model. Is quite simple, actually, and I just wanted to check if there is a good practice established around the subject.

Method 1
Setting the value in the controller, before saving/validating.

public function actionCreate()
{
    $model = new Product();
    $model->attribute = 'My fixed value goes here';
    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        return $this->redirect(['view', 'id' => $model->id]);
    }

    return $this->render('create', [
        'model' => $model,
    ]);
}

Method 2
Filter in rules, inside the model.

public function rules()
{
    return [
        [['attribute'], 'filter', 'filter' => function(){
            return 'My fixed value goes here';
        }],
    ];
}

`
Method 3
init // beforeSave in the model.

public function init()
{
    parent::init();
    $this->attribute = 'My fixed value goes here';
}

Is there any right or wrong about these options?

Welcome to the forum!

Basically all three are valid and which one to choose depends on you and what you need to do with it.

Not sure if in case #3 you mean init() for sure? Because this is quire different from the others - you will have this fixed value almost instantly after initializing the object.

So:

  1. Not fixed to the model. Available immediately. I think it’s most common way.
  2. A bit overkill and you must call validate() to make it work.
  3. Fixed to the model.
    …and if in #3 you mean beforeSave() - you must call save() to make it work, also quite common way.

Hi, Bizley! Thank you for your reply.
Yeah, I haven’t realize that init is executed every time the model is instantiated , so it doesn’t make much sense to set the attribute’s value there. So you’re absolutely correct about beforeSave.

As the idea is to set the attribute’s value fixed to the model ( For example: Product must have created_by = Yii::$app->user->id ) it just seems to me that method #2 is easier to understand the rule. Even if I’d need to call validate because well, I’d probably do it anyway :smile:

But it was good to know that all options - except maybe init() - are valid.

I had my first Yii2 project published in January and I see, now, that I’ve made sooo many mistakes :sweat_smile: So I hope to get enough skills to be able to help people around too.

Best regards,

Usually you would use before save to set last.
For something like created_at or maybe a format change from user input.

public function beforeSave($insert)
    {
        if (!parent::beforeSave($insert)){
            return false;
        }
        $original_tz = date_default_timezone_get();
        date_default_timezone_set('UTC');
        if ($this->isNewRecord){
            $this->created_at = date('Y-m-d H:i:s');
        }

        $this->updated_at = date('Y-m-d H:i:s');

        date_default_timezone_set($original_tz);
        return true;
    }

It will be more likely to be set in a model if it’s a model calling another model.

See the advanced templates frontend/signupForm
It’s taking user input and setting into the actual User model in common like this

    $user->username = $this->username;