Search code examples
phplaravelpostgresqluuid

Laravel model::create() not returning the primary key


I have a following auth table:

<?php

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

class CreateAuthTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('auth', function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->string('email', 255)->index()->unique();
            $table->string('password', 96);
            $table->timestamps();
        });
        DB::statement('ALTER TABLE auth ALTER COLUMN id SET DEFAULT uuid_generate_v4();');
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('auth');
    }
}

And this is the model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;

class User extends Authenticable
{
    use HasApiTokens;

    protected $table = "auth";
    protected $fillable = ["email", "password"];
    public $incrementing = false;
    protected $keyType = 'string';
    protected $casts = [
        'id' => 'string'
    ];

    private $hashOptions = [
        'memory' => 1024,
        'time' => 2,
        'threads' => 1
    ];

    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = Hash::make($value, $this->hashOptions);
    }
}

And in UserController, I create users like so:

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;

class UserController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            "email" => "required|email|unique:auth",
            "password" => "required|string|min:2|max:255",
            "password_confirm" => "required|same:password"
        ]);


        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        $credentials = $request->only('email', 'password');

        $exists = User::where('email', $credentials['email'])->first();
        if ($exists) {
            return response()->json([
                "error" => "Email already exists"
            ], 409);
        }

        $user = User::create($credentials);

        dd($user->id); // This is always null

        return response()->json([
            'data' => [
                "id" => $user->id,
                "email" => $request->email,
            ]
        ]);
    }
}

However, the response $user->id is always null. Shouldn't the Model::create return the id of newly created record?

I also tried a bunch of combinations like so:

// Models\User.php

public $incrementing = false;
protected $keyType = 'string';
protected $casts = [
    'id' => 'string'
];

But the result is always same. I am using Laravel 7 with Postgres SQL 12.3.


Solution

  • Just make sure to have the cast as string and the primary key name correct

    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model
    {
      protected $casts = [
        'id' => 'string'
      ];
      protected $primaryKey = "id";
    }
    

    if you set the $incrementing to false, it will break it and always return false, since it's telling the code that the id is not automatically generated, so never fetched.

    class User extends Model
    {
      public $incrementing = false;
      // ...
    }
    
    $user = new User;
    $user->save();
    dd($user->id);
    // null
    

    Also make sure to enable the uuid extention in migration

    <?php
    
    class AddUuidExtensionToPostgre extends Migration
    {
    
        public function up()
        {
            DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";');
        }
    
        public function down()
        {
            DB::statement('DROP EXTENSION IF EXISTS "uuid-ossp";');
        }
    }
    

    here is an example

    
    Schema::create('users', function (Blueprint $table) {
        $table->uuid('id');
        $table->primary('id');
        // ...
    });
    
    DB::statement('ALTER TABLE users ALTER COLUMN id SET DEFAULT uuid_generate_v4();');