Enhancing Laravel Applications with Traits: A Step-by-Step Guide
Published: 2024-01-17 10:19:06

---
title: Enhancing Laravel Applications with Traits: A Step-by-Step Guide
published: true
date: 2024-01-17 08:17:33 UTC
tags: 
canonical_url: https://dcblog.dev/enhancing-laravel-applications-with-traits-a-step-by-step-guide
---

## What are traits?

Traits are a mechanism for code reuse. Traits allow you to create methods that can be used in multiple classes to avoid code duplication. They are intended to enhance traditional inheritance, enabling you to reuse sets of methods freely in several independent classes living in different class hierarchies.

## Creating a Trait

Traits are classes nothing more, typically you would create them in a `traits` folder or `concerns` which has become quite popular in Laravel. I use a traits folder.

When the traits for written to be used in models I place the traits folder inside a `app/Models` folder.

The skeleton for a trait is as follows:

```php
<?php

namespace App\Models\Traits;

trait HasUuid
{
	public static function booted()
	{
		...
	}

}
```

Like any other class, a trait needs a namespace so it can be loaded.

Next name the trait in this example the trait is called HasUuid.

Inside the traits are either public methods that can be called or like in this case a named function that would be loaded automatically by Laravel using a special `booted` name.

## Usage

To use the above trait in a model. The trait will be imported by calling its namespace `use App\Models\Traits\HasUuid;`

Then inside the class `use` followed by the trait name.

```php
<?php

namespace App\Models;

use App\Models\Traits\HasUuid;

class Setting extends Model
{
    use HasUuid;

    ...
}
```

## A complete UUID trait

In the above examples I’ve mentioned using a trait called `HasUuid`

The complete class:

```php
<?php

namespace App\Models\Traits;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

trait HasUuid
{
    public function getIncrementing(): bool
    {
        return false;
    }

    public function getKeyType(): string
    {
        return 'string';
    }

    public static function booted()
    {
        static::creating(function (Model $model) {
            // Set attribute for new model's primary key (ID) to an uuid.
            $model->setAttribute($model->getKeyName(), Str::uuid()->toString());
        });
    }
}
```

This trait contains 3 methods. In this case, they are all used internally by Laravel.

`getIncrementing` is used to turn off auto-incrementing ids in a database for a primary column.

`getKeyType` is used to override the `getKeyType` method, which is defined in the parent classes/interfaces. In Laravel, the `getKeyType` method is used to specify the data type of the primary key in the model associated with the trait.

In this specific example, the getKeyType method is hard coded to always return the string 'string'. This means that any model using this trait will have its primary key treated as a string type. For instance, if you have a model that uses this trait, and you retrieve its primary key type using `$model->getKeyType()`. it will always return `string` regardless of the actual data type of the primary key column in the database.

`booted` will be called automatically by Laravel, since the method will be called statically it must be defined as a static method.

## Creating a custom trait.

In Laravel you can’t boot multiple traits so instead it's better to name a trait `boot` method in the format of `bootHasName` so a trait called `HasRoles` would be called `bootHasRoles`

This allows booting multiple traits and will still be called automatically when they are used inside other classes.

A common use case is building a multi-tenancy system. Where when a user is logged in then grab a column from the table such as `tenant_id` and then populate any model with the value of the current tenant.

This avoids having to define a tenend\_id any time a model has a create event, this trait will automatically see the create, create, and populate a field called `tenant_id` and then apply a global function so only records matching this tenant will be used.

```php
<?php

namespace App\Models\Traits;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

trait HasTenant
{
    public static function bootHasTenant(): void
    {
        if (auth()->check()) {
            $tenantId = auth()->user()->tenant_id;

            static::creating(function (Model $model) use ($tenantId) {
                $model->tenant_id = $tenantId;
            });

            static::addGlobalScope('tenant', function (Builder $builder) use ($tenantId) {
                $builder->where('tenant_id', $tenantId);
            });
        }
    }
}
```

To use both these examples in a single model:

```php
<?php

namespace App\Models;

use App\Models\Traits\HasTenant;
use App\Models\Traits\HasUuid;
use Illuminate\Database\Eloquent\Model;

class Setting extends Model
{
    use HasTenant;
    use HasUuid;

 	//rest of the model code
}
```

## Conclusion

Traits in Laravel offer a powerful way to reuse code across different classes, thereby reducing code duplication. By utilizing concepts such as the `HasUuid` and `HasRoles` traits, Laravel applications can be made more efficient and maintainable.

Furthermore, Laravel's unique booting mechanism allows for the automatic execution of trait methods, simplifying the implementation of complex functionalities like multi-tenancy. Therefore, understanding and effectively using traits is an essential skill for any Laravel developer.