VertexBuffer's avatar

Model::Create doesn't return model id?

So I've been working on a project recently, and I noticed something that I'm not sure if it's intentional or not but it's incredibly annoying.

I've been explicitly filling my $fillable arrays on my models just for peace of mind as well as because it just seems a lot more descriptive than just disabling it completely.

Well anyway, obviously I don't let my id fields be fillable, but I've now run into the issue that if I call Model::Create, it doesn't return the id. Which is obviously incredibly annoying as I can't really associate it with anything now.

I was wondering whether this was intentional, or a bug, and also what I can do to fix it (OTHER than setting ID to fillable since that just seems like a really bad idea all around to be honest.)

My code looks similar to the below. (Modified slightly for simplification)

    public function store(ModelRequest $request)
    {
        $this->authorize('create', Model::class);

        $model = Model::create($request->validated());

        if ($request->has('properties')) {
            $model->properties()->attach($request->get('properties'));
        }

        $model->load('properties');

        return response()->json($model);
    }

As a side question as well, I'm doing $model->load('properties'); to return the properties association with the json response. Is this the "cleanest" way of doing this, or is there a simpler way?

0 likes
10 replies
mabdullahsari's avatar

When you call create on a model, it doesn't return the id, but a brand new model with the id set in that model, so I'm a bit confused about that. Do you expect to receive an integer from create? You should call $model->getKey()

Your 2nd question, you can manually set the relation on the object so you don't have to hit the database. You already have the properties in this case, so inside your if statement:

$model->setRelation('properties', $request->get('properties'));
2 likes
VertexBuffer's avatar

@mabdullahsari I should mention I'm using UUID, not standard autoincrement id's. I don't know if that has an impact, but if I dd($model) the model itself literally doesn't show the id attribute. $model->getKey() returns null.

The code I said above attach() fails because the model id is null, so yeah. Not really sure what is going on.

mabdullahsari's avatar

Then I can assume that the column uuid in your table is the PK? $model->getKeyName() should return uuid.

Are you creating a brand new uuid when you create those models? Because Laravel won't do that for you. You should also return false in getIncrementing because you are not using AI PKs. Same thing with getKeyType which should return string.

public function getIncrementing()
{
    return false;
}

public function getKeyType()
{
    return 'string';
}
1 like
VertexBuffer's avatar

@mabdullahsari

I set public $incrementing = false; on all of my models.

My migrations id attributes look like this; $table->uuid('id')->default(Str::uuid())->primary()->unique();

Pretty sure I'm doing everything I need to do?

mabdullahsari's avatar
Level 16

Okay, you are mistaken with the default value. That is a fixed default value saved in the database. Str::uuid() will only run once when migrating, that's it. New models won't have new UUIDs. You need to set up an Eloquent event handler for the creating event. I'd recommend to put these in a trait so it is only a matter of importing that trait if another model also needs to use UUIDs. Something like below:

use Illuminate\Support\Str;

trait HasUuid
{
    protected static function bootHasUuid()
    {
        static::creating(static function ($model) {
            if ($model->getKey() === null) {
                $model->setAttribute($model->getKeyName(), (string) Str::uuid());
            }
        });
    }

    public function getIncrementing()
    {
        return false;
    }

    public function getKeyType()
    {
        return 'string';
    }
}
1 like
VertexBuffer's avatar

@mabdullahsari

So I'd use this trait on my model, e.g; Model.php, and then in my migrations I'd use something like this; $table->uuid('id')->primary()->unique();

?

VertexBuffer's avatar

That managed to fix it! I wasn't aware that was the case with UUID. Couldn't find much docs on it so I thought you could just assign the UUID type and Laravel would "magically" handle the rest itself.

Thanks for the clarification! :)

VertexBuffer's avatar

@mabdullahsari

Bit of a bonus question here regarding the UUID's.

Is it possible to take advantage of that HasUuid trait on pivot tables? I'm using UUID in everything EXCEPT pivot tables because every time I try and use them, it complains than the primary key isn't being set.

I tried using the same setup I did to solve the above but no luck, presumably because my pivot table consists of only a migration and not a controller or model!

Please or to participate in this conversation.