Lets say you want to use multiple traits in your models to reuse common code such as applying UUIDs and settings global query scopes like this:
use HasUuid;
use HasTenant;
Each of these traits has a boot method:
HasUuid:
trait HasUuid
{
public function getIncrementing(): bool
{
return false;
}
public function getKeyType(): string
{
return 'string';
}
public static function boot()
{
static::creating(function (Model $model) {
// Set attribute for new model's primary key (ID) to an uuid.
$model->setAttribute($model->getKeyName(), Str::uuid()->toString());
});
}
}
HasTenant:
trait HasTenant
{
public static function boot()
{
if (auth()->check()) {
$tenantId = auth()->user()->tenant_id;
//assign when creating a record
static::creating(function ($query) use ($tenantId) {
$query->tenant_id = $tenantId;
});
//apply condition to all queries
static::addGlobalScope('tenant', function (Builder $builder) use ($tenantId) {
$builder->where('tenant_id', $tenantId);
});
}
}
}
trying to run this will trigger an error:
Trait method App\Models\Traits\HasTenant::boot has not been applied as App\Models\User::boot, because of collision with App\Models\Traits\HasUuid::boot
This is because both traits are using a boot method, to solve this Laravel supports a bootTraitName for example HasTenant becomes bootHasTenant
Change both traits to use the bootTraitName like this:
trait HasUuid
{
public static function bootHasUuid()
{
and
trait HasTenant
{
public static function bootHasTenant()
{
Now they can be used together in a single model without causing any errors.
Laravel also supports initializeTraitName which can look like:
protected function initializeHasToken()
{
$this->token = Str::random(100);
}