Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Laravel - Use UUID For Model ID

The default Laravel setup is for you to be using auto-incrementing integer IDs against a MySQL setup. I prefer to use PostgreSQL with UUIDs for the primary key. This tutorial will show you how you can quickly add a UUID trait, which you can then add to your models, so that they are using a UUID for their primary key/identifier.

Steps

Create a folder inside app called Traits if you haven't already. We will store all traits in here.

mkdir app/Traits

Now we need to create a trait which we will give to your models, in order to "convert" them to being UUID-based for their IDs, rather than an auto incrementing number.

editor app/Traits/TraitUuid

I am using the Trait prefix on the class name because I find this useful when finding files by name in my IDE. I do the same with interfaces and abstract classes.

<?php

namespace App\Traits;

use Illuminate\Support\Str;


trait TraitUuid
{
    /**
     * Override the boot function from Laravel so that 
     * we give the model a new UUID when we create it.
     */
    protected static function boot()
    {
        parent::boot();

        $creationCallback = function ($model) {
            if (empty($model->{$model->getKeyName()}))
            {
                $model->{$model->getKeyName()} = Str::uuid()->toString();
            }
        };

        static::creating($creationCallback);
    }


    /**
     * Override the getIncrementing() function to return false to tell
     * Laravel that the identifier does not auto increment (it's a string).
     *
     * @return bool
     */
    public function getIncrementing() : bool
    {
        return false;
    }


    /**
     * Tell laravel that the key type is a string, not an integer.
     *
     * @return string
     */
    public function getKeyType() : string
    {
        return 'string';
    }
}

Now, to make a model UUID-based, simply add the trait to the model with: use TraitUuid; like so:

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use Notifiable;
    use \App\Traits\TraitUuid;

Updating Migrations

Please note that if you apply the UUID change to the existing User model, then you will need to update your migrations. You should have one called create_users_table.php with the following code:

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

Change this to:

Schema::create('users', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

MariaDB / MySQL Users

If you are using MySQL/MariaDB instead, then you may need to do the following instead:

Schema::create('users', function (Blueprint $table) {
    $table->string('uuid')->primary();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

Stub Customization

To prevent having to add the uuid trait manually to each model whenever you create a new model through artisan, you may wish to customize the stub so that it will automatically be there in future.

References

Last updated: 26th July 2022
First published: 17th September 2021