LARAVEL how to change $fillable in Model from trait?

For anyone that came here looking for an answer; I believe that there is a better way than constructor overloading.

Others have pointed out that Laravel supports bootable model traits, using the boot<TraitName> method you can set up the trait for usage. However, the boot<TraitName> method has to be static, so you cannot alter any non-static properties of the model.

However, I found out that there is a non-static equivalent to the boot<TraitName> method; the initialize<TraitName> method.

Internally, when Eloquent boots up a model, it also registers all initialize methods for the model, based on the methods found in the traits that the model uses. Then upon instantiating that model, the initialize methods are fired.

An example of usage, based on the problem stated in this question:

trait SEOTrait
{
    /**
     * This method is called upon instantiation of the Eloquent Model.
     * It adds the "seoMeta" field to the "$fillable" array of the model.
     *
     * @return void
     */
    public function initializeSEOTrait()
    {
        $this->fillable[] = 'seoMeta';
    }
}

Sadly there isn't any information in the official documentation about either bootable or initializable traits. However, I still find it really cool that both functionalities exist.


I had the same requirement. However, I didn't want to declare a constructor in my trait, as this leads to very unexpected behaviour - what if another trait also declares a constructor?

As pointed out by PeterPan666, we can't use the static trait boot() method to directly set the non-static fillable property - but we can utilise Laravel Model Events, which receive an instance of the model.

For example:

public static function bootSeoTrait() : void
{
    static::retrieved(function($model) {
        $model->fillable = array_merge($model->fillable, ['seoMeta']);
    });
}

Update

Although the $fillable property is protected, the GuardsAttributes trait - which the Illuminate\Database\Eloquent\Model uses - contains the following setter:

/**
 * Set the fillable attributes for the model.
 *
 * @param  array  $fillable
 * @return $this
 */
public function fillable(array $fillable)
{
    $this->fillable = $fillable;

    return $this;
}

So, we can set the $fillable protected property from our model instance in the retrieved event.