Changing the primary key id of a Laravel Model

I once read an article about changing the primary key column id of to the name of your model. So if database was named “items” , your primary id shouldn’t just be named “id” but “item_id”. Building things from scratch, this came in handy. Especially when debugging and joining tables. When you saw an error like “ambiguous name column” and you joined 3 tables, you needed to specify each table name with it’s id. And that’s just one example.

Since I started developing in Laravel I wanted to do this too.
My migration file would look like this

public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id('item_id');
            $table->string('item_name');
            $table->timestamps();
        });
    }

As you can see I added ”item_id” inside of the usual $table->id(”) . Running the migration would rename primary key id to item_id. You would only see the problem when trying to route to the record and most likely get the following error:

Missing required parameter for [Route: item.edit] [URI: items/edit/{item}] [Missing parameter: item]. 

Or when trying to fetch the record you would get:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'where clause' (SQL: select * from `items` where `id` = 1 limit 1)

The Problem:

By default Laravel is searching for the id column, but cannot find it because we renamed the primary key column to item_id

The Solution

You have to (re)define the primary key in the model. In this case my model name is Item, so in app\Models\Item.php you have to add the following:

protected $primaryKey = 'item_id';

The models would then be :

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    protected $primaryKey = 'item_id';

    protected $fillable = [
        'item_id',
        'item_name',
    ];
}

Laravel knows the primary key is now changed to item_id and would then change it’s query .
So by default Laravel would do something like this

select * from `items` where `id` = 1 limit 1

but after redefining the primary key, Laravel will now do this

select * from `items` where `item_id` = 1 limit 1

So that’s how I solved this particular problem and I hope it helps you if you were somehow Googling this.

Happy Programming!