“booting a trait” convention in Laravel to increase performance and keep code clean

Amirnagy
4 min readNov 7, 2023

how to use the boot function in traits in Laravel in models to automatically apply scope and other events when dealing with CRUD operations in Laravel

Introduction

the framework’s ability to seamlessly integrate traits with models strikes a chord with artisans of code.

“to build robust applications with Laravel, models are the cornerstone, managing our application’s data and serving as the relation between our database and business logic. But as our models grow and increase responsibilities, how do we maintain clarity and reusability in our code? Enter Laravel’s traits, a mechanism to extract and encapsulate common behaviors. In this article, we’ll explore the art of ‘booting’ a trait within a Laravel model — a technique that allows traits to hook into a model’s lifecycle events with elegance and ease. Whether you’re a seasoned artisan or new to Laravel’s charm, we’ll guide you through the seamless integration of traits with models, ensuring your codebase remains as efficient and organized as a well-rehearsed symphony, ”

Let’s start

let us suggest we have a problem with our app for example we have an application for school or anything else and we need to apply GlobalScope to only fetch the records of auth user-specific on our model

l know that we have a lot of solutions by using design functions to get only the records of the user but we need when we make

$posts = Post::all();

only return the record of the authentication user so the best solution to use GlobalScope

we also have a lot of solutions to use in the model directly or on service providers but I will use bootable traits

let we see

trait Multitenancy {

/**
* Boot the multitenancy trait for a model.
*
* @return void
*/
public static function bootMultitenancy()
{
// Check if there's an authenticated user
if (auth()->check()) {
// When creating a new model, set the `user_id` to the id of the authenticated user
static::creating(function ($model) {
$model->user_id = auth()->id();
});

// Add a global scope that automatically scopes queries to the authenticated user
static::addGlobalScope('user_id', function (Builder $builder) {
$builder->where('user_id', auth()->id());
});
}
}
}
  • The bootMultitenancy static function within the trait is likely intended to be automatically called upon booting the model that uses the trait. Here's what the code is doing
  • The bootMultitenancy function checks if there is a currently authenticated user by calling auth()->check().
  • If there is an authenticated user, it adds a model event to the creating event, which automatically sets a user_id property on the model to the ID of the currently authenticated user. This is a common pattern for recording in which the user creates a given model instance in a database for auditing or multi-tenant purposes.

It also adds a global scope to the model using addGlobalScope. Global scopes allow you to add constraints to all queries for a given model. In this case, it's checking again for an authenticated user and if one exists, it modifies all queries to only include results where the user_id matches the ID of the currently authenticated user. This is typical for a multi-tenant system where you want each user to only see their own data.

ok, how did this happen?

In Laravel, method names that begin with boot are treated specially. When a model boots up, Laravel looks for any method that is named boot followed by the name of a trait that is being used by the model. If such a method exists, Laravel will automatically call it during the booting process of the model. This behavior is part of Laravel's design and allows for the initialization of traits within a model.

In the case of the bootMultitenancy method you've shown, because it is prefixed with boot and is part of a trait named Multitenancy, Laravel will automatically call this method without the developer needing to manually invoke it. This convention is a part of the Laravel framework's lifecycle hooks which are used to tap into model events, such as when a model is being booted, created, saved, updated, deleted, etc.

So, when a model that uses the Multitenancy trait is instantiated, Laravel's booting mechanism automatically calls bootMultitenancy as part of its initialization sequence, setting up the creating event and global scope as specified in the method. This is standard behavior in Laravel and is documented in the Laravel documentation.

you may say how i can use this returned data.

the first thing we use out traits in out model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Traits\Multitenancy;

class YourModel extends Model
{
use Multitenancy;

// Rest of your model...
}

Now in our controller

we will make create instance

$yourModel = new YourModel();
$yourModel->some_attribute = 'value';
$yourModel->save();

but without setting the Id to post because traits will assign the user id to it by

static::creating(function ($model) {
$model->user_id = auth()->id();
});

now when querying the model, the global scope added by the trait will automatically scope the query to the authenticated user’s user_id, meaning you only get results that were created by the currently authenticated user.

$userModels = YourModel::all(); // Only returns models created by the authenticated user

abstract

“Booting a trait” in Laravel refers to the process of initializing trait behavior in an Eloquent model. When a model boots, Laravel automatically calls methods named boot{TraitName} for each trait used by the model. This feature allows the developer to define trait initialization logic that gets executed as part of the model's lifecycle. The bootMultitenancy method within the Multitenancy trait is an example, where it configures the model to automatically assign the authenticated user's ID during creation and applies a global scope to queries for user-specific data retrieval. This is especially useful in multi-tenant systems to ensure data separation between users.

--

--