laravel カラム追加とインデックス追加と外部キー制約を付与するマイグレーション

## 概要

- カラム追加とインデックス追加と外部キー制約を付与するマイグレーションの書き方を簡単にまとめる。

## 結論

- テーブルを指定してマイグレーションファイルを作成し、下記のように記載する。

    ```php
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::table('テーブル名', function (Blueprint $table) {
                $table->unsignedBigInteger('追加カラム名')
                    ->nullable(false)
                    ->default(99)
                    ->after('type')
                    ->comment('コメント');
                // インデックス
                $table->index('追加カラム名');
                // 外部キー
                $table->foreign('追加カラム名')
                    ->references('id')
                    ->on('payment_balance_categories')
                    ->cascadeOnDelete();
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::table('テーブル名', function (Blueprint $table) {
                // 外部キー制約の削除
                $table->dropForeign('外部キー制約名');
                // インデックスの削除
                $table->dropIndex('インデックス名');
                // カラムの削除
                $table->dropColumn('カラム名');
            });
        }
    };
    ```

## 簡単な解説

- インデックスと外部キー制約は作成時には`カラム名`で指定するが、削除時には`インデックス名`と`外部キー制約名`を指定することに注意する。（テーブル名とカラム名はそれぞれ今マイグレーションで変更を与えようとしているテーブル名とカラム名のことを指す。）
    - インデックス名は自身で設定しなければ`テーブル名_カラム名_index`となる。
    - 外部キー制約名は自身で設定しなければ`テーブル名_カラム名_foreign`となる。
- down側の設定がうまくできていない、もしくは順番が間違えている（カラム削除 → 外部キー制約削除など）になっている場合下記のようなエラーが出ることが有る。マイグレーションはup側（`$ php artisan migrate`）のみではなくdown側（`$ php artisan migrate:rollback`）もエラー無く実行できることを確認しておいたほうが良い。
    - インデックス名や外部キー制約名が誤っている場合のエラーの例

        ```
        PDOException: SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'あなたがインデックス名、もしくは外部キー制約名だと思いこんでいるもの'; check that column/key exists
        ```

    - down内でdropの順番が間違えている場合のエラーの例

        ```
        PDOException: SQLSTATE[HY000]: General error: 1553 Cannot drop index 'インデックス名': needed in a foreign key constraint
        ```

## drop時のインデックスと外部キー制約をカラム名で指定する方法

- 実は下記のように配列で指定することでインデックスと外部キー制約をカラム名で指定する事ができる。

    ```php
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::table('テーブル名', function (Blueprint $table) {
                $table->unsignedBigInteger('追加カラム名')
                    ->nullable(false)
                    ->default(99)
                    ->after('type')
                    ->comment('コメント');
                // インデックス
                $table->index('追加カラム名');
                // 外部キー
                $table->foreign('追加カラム名')
                    ->references('id')
                    ->on('payment_balance_categories')
                    ->cascadeOnDelete();
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::table('テーブル名', function (Blueprint $table) {
                // 外部キー制約の削除
                $table->dropForeign(['カラム名']);
                // インデックスの削除
                $table->dropIndex(['カラム名']);
                // カラムの削除
                $table->dropColumn('カラム名');
            });
        }
    };
    ```