Skip to content
Advertisement

Laravel migration: “Foreign key constraint is incorrectly formed”)

My migration fails when I try to execute php artisan migrate or php artisan migrate:refresh with this error:

errno: 150 "Foreign key constraint is incorrectly formed"

Code

Users Table (migrated successfully)

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->integer('id',)->primary();
        $table->string('name', 255);
        $table->string('surname', 255);
        $table->string('email', 255)->unique();
        $table->string('password', 255);
        $table->string('profile_image', 255);
        $table->string('profile_cover', 255);
        $table->rememberToken();
        $table->char('token', 255)->unique()->nullable()->default(null);
        $table->enum('role', ['user', 'driver', ',merchant', 'storemanager', 'storeoperator', 'company', 'employee']);
        $table->dateTime('created');
        $table->dateTime('updated');
    });
}

Address Table (fails with error)

public function up()
{
    Schema::create('address', function (Blueprint $table) {
        $table->integer('id')->primary();
        $table->string('address1');
        $table->string('address2');
        $table->string('city');
        $table->integer('country')->unsigned();
        $table->decimal('latitude');
        $table->decimal('longitude');
        $table->string('instructions');
        $table->integer('default');
        $table->integer('user')->unsigned();
        $table->dateTime('created');
        $table->dateTime('updated');
        $table->foreign('country')->references('id')->on('country')->onUpdate('cascade');
        $table->foreign('user')->references('id')->on('users')->onUpdate('cascade');

    });
}

Advertisement

Answer

One of the reasons to work with a framework such as Laravel is syntactic sugar. By following their conventions, you write less code and have to think about fewer of the “nuts and bolts” of your application.

You are doing the opposite of this, and are already seeing the consequences. You will experience so much more pain once you try setting up models and their relationships. Instead you should be using a migration that looks like this:

<?php

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

class CreateAddressesTable extends Migration
{
    public function up()
    {
        // table names are plural of the object name
        Schema::create('addresses', function (Blueprint $table) {
            // automatically create an incrementing bigint column called 'id'
            $table->id();
            // name foreign ID columns correctly to save yourself trouble later
            $table->foreignId('country_id')->constrained();
            $table->foreignId('user_id')->constrained();
            // specify lengths for your varchar columns
            $table->string('address1', 100);
            $table->string('address2', 100);
            $table->string('city', 100);
            $table->decimal('latitude');
            $table->decimal('longitude');
            $table->string('instructions', 100);
            $table->integer('default');
            // why would you define your own timestamp columns with non-standard names?
            $table->timestamps();
        });
    }
}

And the users table; you’d want to update its migration similarly.

<?php

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            // DO NOT use an enum column; create another table called roles instead
            $table->foreignId('role_id')->constrained();
            $table->string('name', 100);
            $table->string('surname', 100);
            $table->string('email', 100)->unique();
            $table->string('password', 255);
            $table->string('profile_image', 255);
            $table->string('profile_cover', 255);
            $table->rememberToken();
            // 
            $table->char('token', 255)->unique()->nullable()->default(null);
            $table->timestamps();
        });
    }

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement