Laravel Tip: Bootable Model Traits

Feature image: Laravel Tip: Bootable Model Traits

TL;DR Use bootNameOfTrait() instead of boot() in a model trait to avoid being overwritten by the base model’s boot() method.

Adding behavior through a 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 a deleting 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()

A better way

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!

Get our latest insights in your inbox:

By submitting this form, you acknowledge our Privacy Notice.

Hey, let’s talk.

By submitting this form, you acknowledge our Privacy Notice.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Thank you!

We appreciate your interest. We will get right back to you.