mallorca's avatar

Can't use trait if I have a boot method declared

Hi artisans,

I have a RecordsActivity trait to store some activities and I use that in my model. In my model, I already have this code snippet:

protected static function boot() 
    {
        parent::boot();
        self::deleting(function (Club $club) {
            foreach ($club->users as $users) $users->delete();
        });
    }

What it does is removes all users that belong to the club while softdeleting.

The RecordsActivity trait which also has:

namespace App;

trait RecordsActivity
{
protected static function boot() 
{
parent::boot();
some code...
}
}
}

I can't use them both at the same time. If I remove the first code, RecordsActivity trait doesn't get called. How can I solve this? Thanks!

0 likes
8 replies
thomaskim's avatar
Level 41

If you want to add a boot method to your trait, name your boot method in the following format: bootNameOfTrait.

So, because your trait's name is RecordsActivity, your boot method should be like this:

public static function bootRecordsActivity()
{
    // some code
}
5 likes
mallorca's avatar

@thomaskim Thanks for your reply! However that didn't work for me, I updated the previous reply also.

Now that I change the trait to:

namespace App;

trait RecordsActivity
{
    public static function bootRecordsActivity()
{
parent::boot();
//some code
}
}

I get a server 500 error upon doing the action.

moharrum's avatar

Traits work somehow like inheritance, if the same function is defined inside a trait and a class (in this case your model), the trait method gets overwritten by the class method.

What is the error message you are getting?

1 like
mallorca's avatar

@moharrum Thanks for your reply! After playing around a bit, I figured @thomaskim 's solution worked if I remove

parent::boot(); 

after changing the trait to public static function bootNameOfTrait

moharrum's avatar

Hi @Augustus , call bootRecordsActivity() inside boot()

protected static function boot() 
    {
        parent::boot();
        // ... Do something ...
        // Call self::bootRecordsActivity()
        self::bootRecordsActivity();
    }

Don't forget to remove the call to parent::boot() in bootRecordsActivity(), since you already called it in boot(). And check for the error stack trace in storage/logs/laravel.log

1 like
mallorca's avatar

@moharrum Thanks for your reply! That's great, gives me new perspectives. Yeah, removing the parent::boot() seemed to fix it for me.

I guess the way you describe it, I should add the self::bootRecordsActivity(); below the models parent::boot() that I had already created? Or perhaps in the EventServiceProvider?

Right now, I have

use RecordsActivity

Above the protected static function boot() in the model calling the trait and it seems to fork fine for now, is there any difference using the way you described above?

thomaskim's avatar

@Augustus Don't call boot() anywhere in your trait. Don't call bootRecordsActivity inside the boot method either.

Laravel designed it specifically because of issues like this. You'll see this line of code in your model's boot method:

protected static function boot()
{
    static::bootTraits();
}

It already takes care of booting your traits, and you shouldn't try to override this in your trait or whatever. Otherwise, you can't have a boot method inside your own models.

1 like

Please or to participate in this conversation.