DEV Community

Nasrul Hazim Bin Mohamad
Nasrul Hazim Bin Mohamad

Posted on

Using the `InteractsWithUuid` Trait to Manage UUIDs in Laravel

In modern web applications, using UUIDs (Universally Unique Identifiers) as primary keys offers several advantages over traditional auto-incrementing integers, such as better security, easier data replication, and ensuring uniqueness across distributed databases. Laravel makes it easy to work with UUIDs, and using traits can make the implementation even more straightforward.

In this blog post, we'll dive into a custom InteractsWithUuid trait that simplifies the use of UUIDs in Laravel models, how to set it up, and how to customize it for your specific needs.

The InteractsWithUuid Trait Explained

The InteractsWithUuid trait provides functionality for automatically generating UUIDs for your models, using UUIDs as route keys, and adding query scopes for searching by UUID. Here is the code for the trait:

namespace App\Concerns;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

trait InteractsWithUuid
{
    public static function bootInteractsWithUuid()
    {
        static::creating(function (Model $model) {
            if (Schema::hasColumn($model->getTable(), $model->getUuidColumnName()) && is_null($model->{$model->getUuidColumnName()})) {
                $model->{$model->getUuidColumnName()} = Str::orderedUuid();
            }
        });
    }

    /**
     * Get the route key for the model.
     */
    public function getRouteKeyName(): string
    {
        return $this->getUuidColumnName();
    }

    /**
     * Get UUID Column Name.
     */
    public function getUuidColumnName(): string
    {
        return isset($this->uuid_column) ? $this->uuid_column : 'uuid';
    }

    /**
     * Scope a query to include only by UUID.
     */
    public function scopeUuid(Builder $query, $value): Builder
    {
        return $query->where($this->getUuidColumnName(), $value);
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Features of the InteractsWithUuid Trait

  1. Automatic UUID Generation:

    • The bootInteractsWithUuid method listens to the creating event of the model and automatically assigns a UUID to the model if it is not already set. It uses Str::orderedUuid() to generate the UUID, which is a time-ordered UUID string, providing better performance for indexing in databases.
  2. Custom Route Key:

    • By overriding the getRouteKeyName method, the trait ensures that the UUID column is used as the route key, allowing you to use UUIDs in route model binding seamlessly.
  3. Customizable UUID Column:

    • The getUuidColumnName method allows for a customizable UUID column name. By default, it looks for a column named uuid, but you can override this by defining a $uuid_column property in your model.
  4. Query Scope for UUID:

    • The scopeUuid method allows you to query models by UUID, providing a convenient way to filter records.

How to Use the InteractsWithUuid Trait in Your Models

To use the InteractsWithUuid trait, you simply need to import it into your model:

namespace App\Models;

use App\Concerns\InteractsWithUuid;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use InteractsWithUuid;

    // Optionally, specify a custom UUID column name
    protected $uuid_column = 'custom_uuid';
}
Enter fullscreen mode Exit fullscreen mode

Example Migration for UUID with Index

To use the InteractsWithUuid trait effectively, you need to add a UUID column to your database table. Here’s an example migration for a posts table that includes a UUID column with an index:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->uuid('uuid')->unique(); // Add a UUID column with a unique index
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
Enter fullscreen mode Exit fullscreen mode

Customizing the UUID Field

If you need to customize the UUID column, you can easily do so by modifying the $uuid_column property in your model. For example, if you want to use a column named custom_uuid instead of the default uuid:

namespace App\Models;

use App\Concerns\InteractsWithUuid;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use InteractsWithUuid;

    // Specify the custom UUID column name
    protected $uuid_column = 'custom_uuid';
}
Enter fullscreen mode Exit fullscreen mode

And then adjust your migration accordingly:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->uuid('custom_uuid')->unique(); // Custom UUID column name
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

The InteractsWithUuid trait is a powerful and flexible way to manage UUIDs in your Laravel applications. By providing automatic UUID generation, customizable UUID columns, and query scopes, it simplifies the process of using UUIDs as primary keys or route keys. With the examples provided, you can easily integrate this trait into your Laravel models and customize it to fit your specific needs.

Top comments (0)