Skip to content

Instantly share code, notes, and snippets.

@Razoxane
Created August 8, 2017 01:35
Show Gist options
  • Select an option

  • Save Razoxane/3bc74900b4eb5c983eb0927fa13b95f5 to your computer and use it in GitHub Desktop.

Select an option

Save Razoxane/3bc74900b4eb5c983eb0927fa13b95f5 to your computer and use it in GitHub Desktop.
Laravel - Create Index If Not Exists / Drop Index If Exists
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class LaravelConditionalIndexMigration extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tablename', function (Blueprint $table) {
$sm = Schema::getConnection()->getDoctrineSchemaManager();
$doctrineTable = $sm->listTableDetails('tablename');
if (! $doctrineTable->hasIndex('singlecolumnindexname')) {
$table->index('column1', 'singlecolumnindexname');
}
if (! $doctrineTable->hasIndex('multicolumnindexname')) {
$table->index(['column2', 'column3'], 'multicolumnindexname');
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tablename', function (Blueprint $table) {
$sm = Schema::getConnection()->getDoctrineSchemaManager();
$doctrineTable = $sm->listTableDetails('tablename');
if ($doctrineTable->hasIndex('singlecolumnindexname')) {
$table->dropIndex('singlecolumnindexname');
}
if ($doctrineTable->hasIndex('multicolumnindexname')) {
$table->dropIndex('multicolumnindexname');
}
});
}
}
@Benjaminhu

Copy link
Copy Markdown

I'm glad I found this, because that's exactly what I was looking for! Thanks for the comments!
I made a portable/reuseable solution for it (app/Domain/Migration/MigrationUtil.php):

<?php

declare(strict_types=1);

namespace App\Domain\Migration;

use Doctrine\DBAL\Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class MigrationUtil
{
    /**
     * INFO: https://gist.github.com/Razoxane/3bc74900b4eb5c983eb0927fa13b95f5
     *
     * @throws Exception
     */
    public static function hasIndex(string $tableName, string $indexName): bool
    {
        $doctrineSchemaManager = Schema::getConnection()->getDoctrineSchemaManager();

        return $doctrineSchemaManager->introspectTable($tableName)->hasIndex($indexName);
    }
}

usage:

<?php

declare(strict_types=1);

use App\Domain\Migration\MigrationUtil;
use Illuminate\Database\Migrations\Migration;

return new class() extends Migration {
    public function up(): void
    {
        Schema::table('users', static function ($table) {
            if (MigrationUtil::hasIndex('users', 'unique_email')) {
                $table->dropUnique('unique_email');
            }
            if (!MigrationUtil::hasIndex('users', 'users_email_unique')) {
                $table->unique('email');
            }
        });
    }
};

@mbuyco

mbuyco commented Sep 4, 2024

Copy link
Copy Markdown

Thanks! Great stuff 🙇‍♂️ 💯

@daniellesniak

Copy link
Copy Markdown

In Laravel 11 Symfony's DBAL has been replaced by Laravel's native classes so above solutions does not work anymore. Here's the working dropIndexIfNotExists for Laravel 11.

<?php

namespace App\Traits;

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

trait MigrationIndex
{
    public function dropIndexIfExist(string $tableName, string $indexName): void
    {
        $indexes = Schema::getIndexes($tableName);

        foreach ($indexes as $index) {
            if ($index['name'] === $indexName) {
                Schema::table($tableName, static function (Blueprint $table) use ($indexName) {
                    $table->dropIndex($indexName);
                });
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment