1

I have 2 migrations, the first one has the following name 2019_11_06_171637_create_settings_table.php and structure:

class CreateSettingsTable extends Migration
{
  public function up()
  {
    Schema::create('settings', function (Blueprint $table) {
      //code
    });
  }
  //function down
}

the second one has the following name 2020_07_08_246856_create_settings_table.php and structure:

class CreateAnotherSettingsTable extends Migration
{
  public function up()
  {
    Schema::create('another_settings', function (Blueprint $table) {
      //code
    });
  }
  //function down
}

When I run php artisan migrate all migrations going well until Migrating: 2020_07_08_246856_create_settings_table - it's trying to run the previos migration(2019_11_06_171637_create_settings_table.php) and fire an exception Table 'settings' already exists.

Does this mean that the name of the migration file must be unique after the date and numbers?

hehoboy
  • 75
  • 1
  • 7
  • 1
    Can you rename the second file to `2020_07_08_246856_create_another_settings_table.php`? If I remember correctly it uses the filename to look for the correct class name. – Douwe de Haan Sep 09 '20 at 09:50
  • @Douwe de Haan, yeap, you are right! Renaming is a little bit an issue for me since I trying combine migrations from two projects but there is no other way, thanks. – hehoboy Sep 09 '20 at 09:54
  • 1
    @hehoboy I've added an answer so you can mark it as accepted. If renaming isn't possible, maybe try to combine multiple migrations in one single file, so you can run it as one migration (if you don't have to keep the history in version control). – Douwe de Haan Sep 09 '20 at 09:59
  • 1
    @hehoboy to add to my previous comment: Laravel 8 (which was released yesterday) has migration squashing which could resolve some migration issues possibly ([documentation here](https://laravel.com/docs/8.x/migrations#squashing-migrations)) – Douwe de Haan Sep 09 '20 at 10:02

2 Answers2

1

I've read somewhere that Laravel uses the filenames of migrations to call the correct class for the migration. I've tried to look up some documentation or reference on this, but I can't find it anymore. You currently have the same filename twice (if you ignore the timestamp part) which results in Laravel calling the same class twice.

If you rename the second file (the one with the CreateAnotherSettingsTable class) to 2020_07_08_246856_create_another_settings_table.php, your problem will be fixed.

Douwe de Haan
  • 6,247
  • 1
  • 30
  • 45
1

I found this very interesting so I looked within the source code.

\Illuminate\Database\Console\Migrations\TableGuesser will use the migration name to determine whether if the table already exists.

        // Next, we will attempt to guess the table name if this the migration has
        // "create" in the name. This will allow us to provide a convenient way
        // of creating migrations that create new tables for the application.
        if (! $table) {
            [$table, $create] = TableGuesser::guess($name);
        }

This is executed upon artisan:make and migrate:install commands.

So ultimately, as your migration file name is create_settings_table.php, the "settings" word is what will be used for checking.

The code that laravel uses for this determination is:

    const CREATE_PATTERNS = [
        '/^create_(\w+)_table$/',
        '/^create_(\w+)$/',
    ];

    const CHANGE_PATTERNS = [
        '/_(to|from|in)_(\w+)_table$/',
        '/_(to|from|in)_(\w+)$/',
    ];

    /**
     * Attempt to guess the table name and "creation" status of the given migration.
     *
     * @param  string  $migration
     * @return array
     */
    public static function guess($migration)
    {
        foreach (self::CREATE_PATTERNS as $pattern) {
            if (preg_match($pattern, $migration, $matches)) {
                return [$matches[1], $create = true];
            }
        }

        foreach (self::CHANGE_PATTERNS as $pattern) {
            if (preg_match($pattern, $migration, $matches)) {
                return [$matches[2], $create = false];
            }
        }
    }

So your solution is to rename one of those migration files.

CreateAnotherSettingsTable will be the best, standard following, name

PatricNox
  • 3,306
  • 1
  • 17
  • 25