I have in model:
use seoTrait;
protected $fillable = [
'name', 'title', 'description'
];
I created trait "seoTrait" which need "seoMeta" in $fillable.
Now I add :
protected $fillable = [
'name', 'title', 'description', 'seoMeta'
];
But is it possible in trait "seoTrait" add something to $fillable ?
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.
Since Laravel 5.7, you can initialize a model trait with a magic initializeTraitName
method on the trait which allow access to the model instance.
trait SeoTrait
{
public function initializeSeoTrait()
{
$this->fillable[] = 'seoMeta';
}
}
You can use constructor inside your trait, but it is important to send fillable attributes to parent constructor Illuminate\Database\Eloquent\Modal
parent::__construct($attributes);
Here is example code:
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->fillable[] = 'seoMeta';
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With