A New Syntax For Foreign Keys in Laravel 7

Arie Visser • May 16, 2020

laravel php database

Since 7.x, Laravel provides a very compact syntax for creating foreign key constraints with the constrained method. In this post we will give a short demonstration of this syntax, and we will take a look at how the constrained function is written in Laravel's source code.

When you want to reference a user in an orders table, you can now write:

Schema::table('orders', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
});

Instead of:

Schema::table('orders', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id');

    $table->foreign('user_id')->references('id')->on('users');
});

How does the constrained method work?

Since the foreignId method is just an alias for unsignedBigInteger, the magic happens in the constrained method. Let's take a look at how this works.

The method can be found in Illuminate\Database\Schema\ForeignIdColumnDefinition:

use Illuminate\Support\Str;

public function constrained($table = null)
{
    return $this
        ->references('id')
        ->on($table ?: Str::plural(Str::before($this->name, '_id')));
}

When calling the constrained method, the column in the child table will always reference to the id column of the parent.

In the on method, the pluralization of the characters before "_id" results in the table name of the parent.

In the case of user_id, this will result in users.

When this conversion would not lead to the correct table name, it is also possible to pass another table name as argument:

Schema::table('orders', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained('app_users');
});

As you can see in the constrained method, when the $table argument is not null, pluralization will not be applied.