かきノート

【Laravel】migration にて、カラムの型を enum に change できない。

July 27, 2021 • ☕️ 5 min read

【 環境 】
Laravel のバージョン: 8.16.1
PHP のバージョン: 7.4.7
MySQL のバージョン: 5.7

Laravel にて、migration ファイルにて DB のカラムの型を変えるコードを書き、migration をすると、エラーが発生する。

具体的には以下のようなコード。

    Schema::table('authors', function (Blueprint $table) {
        $table->enum('gender_type', [1, 2, 3])->nullable()->default(null)->change();
    });

出てきたエラーメッセージ、こんな感じ。

Unknown column type “enum” requested. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType().

You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database

introspection then you might have forgotten to register all database types for a Doctrine Type.

Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes().

If the type name is empty you might have a problem with the cache or forgot some mapping information.

どういう事じゃい。
と思って調べたら、こんなの出てきた。

どうやら、change() メソッドでカラムの型を enum に変更する事は出来ないみたい。

理由は、DBAL 2.9.2は列挙型データ型をサポートしていないからだそうです。

とのこと。

標準では不可、という事で、以下解決策。

解決策1.DB::statement を使い、Alter table を実行する

こんな感じ。

    DB::statement("ALTER TABLE authors MODIFY COLUMN gender_type ENUM('1', '2', '3')");

個人的には、なるべくやりたくない。
理由は、RDB個別の処理になるから。
RDB が MySQL → Postgres に変わってしまった場合、動かないコードが出来てしまう。

なので、エラーが発生しないようにするためには、以下のように RDB による制限が必要となってしまう。
例えば、こんな感じ。

    public function up()
    {
        // MySQL 出なかった場合、早期リターンして、Alter table コマンド(RDB固有のコマンド)を実行しない
        if (DB::getDriverName() !== 'mysql') {
            return;
        }

        DB::statement("ALTER TABLE authors MODIFY COLUMN gender_type ENUM('1', '2', '3')");
    }

「コメントを追加する」といった程度の、アプリにクリティカルな影響を与えない処理なら別に問題ないんじゃないかと思っている。

しかし、こんな事をしても、この場ではエラーが出なくとも、後続の処理でエラーが発生する事は十分にあるし、そもそもアプリがマトモに動かない可能性もあるので、素直にこの時点でエラー出しておいた方が良さそうな気がする。

解決策2.一時カラムを利用する

こちらで紹介されている内容。
【MySQL×Laravel】 ENUM型カラムを扱うなら、マイグレーションの面倒さを覚悟しようという話

手はずとしては、以下のようになります。

  • 現行カラムと同定義の一時カラムを作成
  • 現行のカラム値で一時カラムを上書き
  • 現行カラムを削除
  • 定義できる文字列が追加された状態で現行と同名の新規カラムを作成
  • 一時カラムの値で新規カラムを上書き
  • 一時カラムを削除

なかなかヘビーな力業だ。

コード記述量も増えるし、あんまりやらない方がいいんじゃないのか。

解決策3.enum に change できるようになるライブラリを入れる

こちらで紹介されている内容。
【MySQL×Laravel】 ENUM型カラムを扱うなら、マイグレーションの面倒さを覚悟しようという話

doctrine/dbal というライブラリを使えば、コマンドを有効化できるらしい。

(Doctrine DBAL)
https://github.com/doctrine/dbal

Laravel 公式サイトでも紹介されている。
https://laravel.com/docs/8.x/migrations#modifying-columns

そういえば見覚え・・・と思って調べてみたら、renameColumn でエラー出た時に使ってた。

$table->renameColumn('from', 'to');

カラム名を変更する時、renameColumn というメソッドを使うが、実はデフォルトでは動かないので、doctrine/dbal を composer install していた。

これぐらい、標準サポートしてないのか・・? と思いつつも、入れないと動かないんだから仕方ない。

スマートに解決するのが、こっちが一番いい気がする。


Relative Posts:

【Laravel】バックグラウンド処理のついて整理してみる1(イベントとリスナー)

August 1, 2021

【Laravel】発行した SQL文 のパラメータを、「?」でなく指定した変数をセットして出力する

July 26, 2021

福岡の物流エンジニアが、七転び八起きしたあと九回転び、寝っ転がったまま何かやってる事を垂れ流しているブログ

RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon