Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

alfrednutile's avatar

Using uuid for the id and getting it returned after Create or Save

In many projects we swap out the self incrementing id with a uuid by using the library Rhumsaa\Uuid\Uuid::uuid4()->toString()

This is great overall especially with a AppServiceProvider.php boot to set this id if it is not there.

        User::creating(function ($user) {
            if ( ! $user->id) {
                $user->id = Uuid::uuid4()->toString();
            }
        });

BUT typically in Laravel I can do this

$user = new User();
$user->name = "foo";
$user->save();

echo $user->id;

And get the new id made in this case 1 or 2 if it was self incrementing, BUT it always outputs 0 if I am using this uuid setup even though it saves just fine.

Just a note on the model class I set $incrementing to false since it is not incrementing.

Anyways is there a way to get the id after save if I am not using self incrementing ids? Maybe I am missing some setting or obvious step?

Thanks

0 likes
15 replies
jimmck's avatar

Hi, I am not an Eloquent user except for Auth tables. But I think when you do the getId the magic __get method bounces you here.

    /**
     * Determine if the given relation is loaded.
     *
     * @param  string  $key
     * @return bool
     */
    public function relationLoaded($key)
    {
        return array_key_exists($key, $this->relations);
    }

Thank you for pointing out this package as I just added it to my own Sequence Generator class for MySQL. It would be nice if Model would allow an override for increment for exactly what you are asking. A simple callback to set the id value would suffice, I would think.

Snapey's avatar

don't you generate the uuid first and then pass it to the model before save?

1 like
alfrednutile's avatar

@Snapey yes as seen in the AppServiceProvider.php I show above. But this still does not help on the returning of the model just made. :(

@jimmck maybe I can make a class that extends the class that relationLoaded is in and add that type of functionality. I will look more in a bit.

Snapey's avatar

Are you sure that the service provider is being called? Can you dd $user at that point?

michaelpittino's avatar

Hm, my function looks like this:

public function boot()
{
   \App\User::creating(function (\App\User $user) {
      $user->id = \App\Libraries\IdentifyLibrary::generateGuid();
   });
}

And it works fine :)

Edit: I wrote a little ServiceProvider which handles this:

class IdentifierGenerationServiceProvider extends ServiceProvider
{

    private $models = [
        '\App\User',
        '\App\Profile'
    ];

    public function boot()
    {
        foreach ($this->models as $modelClass)
        {
            $modelClass::creating(function($model) {
                $model->id = \App\Libraries\IdentifyLibrary::generateGuid();
            });
        }
    }

    public function register()
    {

    }

}

Whenever I create a new model which got a string id field I add the class to the $models array.

1 like
psyopus's avatar

@michaelpittino old thread i know, but i can't seem to get this to work.

i created and registered the serviceprovider as per example above but maybe it doesnt do what i hoped it does.

when i change the User model id field to:

$table->string('id',8)->unique();

and the boot function to:

foreach ($this->models as $modelClass)
        {
            $modelClass::creating(function($model) {
                $model->id = newSelector();
            });
        }

(where newSelector() just contains return bin2hex(random_bytes(4)); )

and rerun my migrations and seeds i get:

SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value (SQL: insert into `users` (`name`, `email`, `password`, `entity_id`, `created_at`)  etc..

what i'm looking for is that when ever a new user is created it automatically gets the random string as id.

if i understand the docs correctly creating() should be executed at every insert statement, no?

anything i'm missing here?

psyopus's avatar

ok, seems to work just fine after all but just not with seeds.. which makes kinda sense. you'd have to manually call your random data function:

        User::find(   
            DB::table('users')->insertGetId([
                'selector'    => bin2hex(random_bytes(4)),                
        ...
                'created_at' => date("Y-m-d H:i:s")            
            ])    
        )->assignRole('accountmanager');  

beware, im using random data and this will not work with 'ID' field.

first of all, the ID field needs to be autoincrement for functions like insertGetId() to keep working.

second, you could figure you never use insertGetId or will work around it. this is possible... but keep in mind that a lot of other packages might make use of the User model and expect to link it to ID filed with a foreign key like: int user_id

this will all break when re-configuring id field from int to text.

you could think you could in this case add this to User model:

    protected $primaryKey = 'selector';

but this doesnt change anything... this will still break aforementioned arguments.

my approach is to keep the default ID field and simply add an extra field called 'selector' and use that for referencing/editing users so a edit resource link becomes: /users/4b35b138/edit instead of /users/2/edit for example.

you need to adapt your update method to handle to selector instead of id:

    public function update(Request $request, $locale, $selector) {

    //$user = User::findOrFail($id);    // no longer works

    $user = User::where('selector', $selector)->firstOrFail();  // new way
    
    ...

hope this helps others looking for the same solution

gerritsevilla's avatar

alfrednutile

Did you ever got this working??

No problem generating uuid on model creation the problem is getting the model id just after creation

Thnx

Tippin's avatar

@gerritsevilla Ever since laravel merged Ramsey package into their Str::class facade, I have no issue using the uuid->toString method on model creating. I have immediate access to $model->id after it has been saved, or called using create(). Check out my trait I use on my models with UUIDs:

<?php

namespace App\Traits;

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

trait Uuids
{
    /**
     * On model creating, set the primary key to UUID
     */
    public static function bootUuids()
    {
        static::creating(function (Model $model) {
            $model->{$model->getKeyName()} = Str::orderedUuid()->toString();
        });
    }
}

I just tested making 2 users, and dumping ID out, and it worked:

        $test = User::create([
            'first' => 'Derpy',
            'last' => 'Herpy',
            'slug' => '12345',
            'active' => 1,
            'email' => '[email protected]',
            'password' => 'password'
        ]);

        dump($test->id);

//"91e85023-4508-4c90-972b-5298e1768702"

        $test2 = new User();
        $test2->first = 'nope';
        $test2->last = 'never';
        $test2->slug = '8888';
        $test2->active = 1;
        $test2->email = '[email protected]';
        $test2->password = '987987987';
        $test2->save();

        dump($test2->id);

//"91e85023-55a7-46e0-801c-8fa9ed9a846a"
1 like
Azamanaza's avatar

Late by several years, but have you try adding this in your model?

protected $keyType = 'string';

dennohdee's avatar

Its years later but this will help someone. For Uuid, getting created id returns 0. Add public $incrementing = false; to your model. This is beacuse laravel models by default increments.

4 likes

Please or to participate in this conversation.