CakePHP3: マイグレーションでカラムの型を string から uuid に変更

試行錯誤したのでメモ。もっとシンプルな方法があると思う。。

ドキュメント

作業ログ

    public function change()
    {
        $this->table('hoges')
            ->changeColumn(
                'foo_column',
                'uuid',
                [
                    'null' => false,
                ]
            )
            ->save();
    }

↑ ではうまく行かず、↓のようにした。

// app/config/Migrations/20191212094639_AlterHoges.php 

<?php
use Migrations\AbstractMigration;
use Cake\Utility\Text;
class AlterHoges extends AbstractMigration
{
    public function up()
    {
        // changeColumn() でカラムの型を string から uuid に変更すると、下記のエラーになる為、一度カラムを削除して、追加し直している
        // PDOException: SQLSTATE[42804]: Datatype mismatch: 7 ERROR:  column "foo_column" cannot be cast automatically to type uuid
        $this->table('hoges')
            ->removeColumn(
                'foo_column',
            )
            ->save();
        $this->table('hoges')
            ->addColumn(
                'foo_column',
                'uuid',
                [
                    'null' => true, //既存データがある場合を考慮して、一旦nullを許可
                    'after' => 'hoge_column',
                ]
            )
            ->update();
        $this->updateApiKey();
        $this->table('hoges')
            ->changeColumn(
                'foo_column',
                'uuid',
                [
                    'null' => false,
                    'after' => 'hoge_column',
                ]
            )
            ->save();
    }
    // change() の場合、rollback 時に下記エラーになる為、 up() と down() を使用
    // Exception: Cannot reverse a "Phinx\Db\Action\RemoveColumn" command in [/srv/app/vendor/robmorgan/phinx/src/Phinx/Db/Adapter/ProxyAdapter.php, line 124]
    public function down()
    {
        $this->table('hoges')
            ->changeColumn(
                'foo_column',
                'string',
                [
                    'null' => false,
                    'limit' => 256,
                ]
            )
            ->save();
    }
    /**
     * note: 本来、app/src/Model/Table/HogesTable.php にメソッド追加したかったが、
     *       https://github.com/cakephp/migrations/issues/370 のバグの為、
     *       migration ファイル内に TableRegistry を使用しない方法で実装
     */
    public function updateApiKey()
    {
        $hoges = $this->fetchAll('SELECT id FROM hoges');
        foreach ($hoges as $hoge) {
            $sql = 'UPDATE hoges SET foo_column = \''. Text::uuid() . '\' WHERE id = ' . $hoge['id'];
            $this->execute($sql);
        }
    }
}