Search code examples
laravellaravel-migrations

Why $table->dropForeign raised error in rollback?


I made a migration in Laravel 10.48.14 app :

<?php

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

return new class extends Migration {
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('user_meetings', function (Blueprint $table) {
            $table->foreignId('prior_user_meeting_id')->nullable()->references('id')->on('user_meetings')->onUpdate('cascade')->onDelete('cascade')->after('user_quiz_request_id');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('user_meetings', function (Blueprint $table) {
            $table->dropForeign(['user_meetings_prior_user_meeting_id_foreign']);
            $table->dropColumn('prior_user_meeting_id');
        });
    }
};

and after running it I have a table with valid "prior_user_meeting_id" field and "user_meetings_prior_user_meeting_id_foreign" constraint :

CREATE TABLE `user_meetings` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `branch_id` smallint unsigned NOT NULL,
  `user_id` bigint unsigned DEFAULT NULL,
  `user_quiz_request_id` bigint unsigned NOT NULL,
  `appointed_at` datetime DEFAULT NULL,
  `duration` smallint DEFAULT NULL COMMENT 'duration of meeting in minutes',
  `status` enum('A','P','N','H','M','R') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'A => Meeting is appointed, P => Meeting is postpoined, N-Next meeting is appointed, H=>Employee is hired, M=>Marked for future contacts, R-Rejected',
  `description` mediumtext COLLATE utf8mb4_unicode_ci,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `prior_user_meeting_id` bigint unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_meetings_user_id_foreign` (`user_id`),
  KEY `user_meetings_user_quiz_request_id_foreign` (`user_quiz_request_id`),
  KEY `user_meetings_4_indices_1` (`branch_id`,`status`,`user_id`,`appointed_at`),
  KEY `user_meetings_4_indices_2` (`branch_id`,`user_quiz_request_id`,`user_id`,`status`),
  KEY `user_meetings_prior_user_meeting_id_foreign` (`prior_user_meeting_id`),
  CONSTRAINT `user_meetings_branch_id_foreign` FOREIGN KEY (`branch_id`) REFERENCES `branches` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `user_meetings_prior_user_meeting_id_foreign` FOREIGN KEY (`prior_user_meeting_id`) REFERENCES `user_meetings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `user_meetings_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
  CONSTRAINT `user_meetings_user_quiz_request_id_foreign` FOREIGN KEY (`user_quiz_request_id`) REFERENCES `user_quiz_requests` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

but making rollbacki got error :

$ php artisan migrate:rollback

   INFO  Rolling back migrations.

  2024_07_23_070015_modify_user_meetings_table ............................................................................................ 8ms FAIL

   Illuminate\Database\QueryException

  SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'user_meetings_user_meetings_prior_user_meeting_id_foreign_foreign'; check that column/key exists (Connection: mysql, SQL: alter table `user_meetings` drop foreign key `user_meetings_user_meetings_prior_user_meeting_id_foreign_foreign`)

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:829
    825▕                     $this->getName(), $query, $this->prepareBindings($bindings), $e
    826▕                 );
    827▕             }
    828▕
  ➜ 829▕             throw new QueryException(
    830▕                 $this->getName(), $query, $this->prepareBindings($bindings), $e
    831▕             );
    832▕         }
    833▕     }

      +9 vendor frames
  10  database/migrations/2024_07_23_070015_modify_user_meetings_table.php:23
      Illuminate\Support\Facades\Facade::__callStatic()

      +24 vendor frames
  35  artisan:35

which syntx is valid ?


Solution

    1. As per official docs ,the foreign key constraint name is based on the name of the table (in your case user_meetings) and the columns in the constraint, followed by a _foreign suffix.

    2. Or you can only pass the foreign_key column-name (in your case prior_user_meeting_id) in the form of array into the dropForeign() method.

    So either use this without passing value in the array if you follow 1st approach...

    $table->dropForeign('user_meetings_prior_user_meeting_id_foreign');
    

    Or if you follow 2nd approach use this...

    $table->dropForeign(['prior_user_meeting_id']);
    

    By default array [prior_user_meeting_id] will be converted into foreign key constraint name using Laravel's constraint naming conventions (i.e. user_meetings_prior_user_meeting_id_foreign) if you pass it as an array-format.

    For detailed understanding you can check the official docs link I shared above.