TL;DR Use bootNameOfTrait()
instead of boot()
in a model trait to avoid being overwritten by the base model’s boot()
method.
Let’s say you have a HasImage
trait for every model that is related to an image:
trait HasImage{ public function image() { return $this->belongsTo(Image::class); }}
…and you need to ensure that the image gets deleted when the model is deleted, so you add a boot()
method in the trait.
The static
boot()
method is automatically run whenever a model is instantiated, so it is often an ideal place to add behavior or event bindings--such as, in this case, automatically deleting an image whenever adeleting
event occurs on the model.
public static function boot(){ // Delete associated images if they exist. static::deleting(function ($model) { $model->image->delete(); });}
However, this is problematic if the parent model also contains a boot()
method, as the trait’s method will be overwritten.
The solution? bootHasImage()
instead of boot()
trait HasImage{ public static function bootHasImage() { // Delete associated images if they exist. static::deleting(function($model) { $model->image->delete(); }); } public function image() { return $this->belongsTo(Image::class); }}
This works because of the following snippet taken from Eloquent’s Model.php
.
protected static function boot(){ static::bootTraits();} /** * Boot all of the bootable traits on the model. * * @return void */protected static function bootTraits(){ $class = static::class; foreach (class_uses_recursive($class) as $trait) { if (method_exists($class, $method = 'boot' . class_basename($trait))) { forward_static_call([$class, $method]); } }}
We’ve now unlocked the power of hooking into model events in specific traits.
Enjoy!
We appreciate your interest.
We will get right back to you.