CakePHP Migrations の limit オプションについて


これは CakePHP Advent Calendar 2017 の第14日目の記事です。
CakePHP の Slackチャンネル話題に上がっていたので前倒しで公開します。

三行

  • CakePHP の Migrations は、XXXXINT 系のカラムが苦手な模様。
  • とりあえず対応は可能。
  • 多分、根本的な解決には CakePHP 本体の対応が必要

発端

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `gender` tinyint(4) NOT NULL DEFAULT '0',
  `created` datetime,
  `modified` datetime,
  PRIMARY KEY (`id`)
); 

上記 schema で bake migration_snapshot したマイグレーションファイルを実行すると、以下の例外が投げられてマイグレーションが実行できない。

Exception: An invalid column type "tinyinteger" was specified for column "gender". in [/path/to/vendor/robmorgan/phinx/src/Phinx/Db/Table.php, line 351]

とりあえずの対応方法

該当のカラムの type を変更し、limit に Phinx のオプションを設定する。
http://docs.phinx.org/en/latest/migrations.html#limit-option-and-mysql

-            ->addColumn('gender', 'tinyinteger', [
+            ->addColumn('gender', 'integer', [
                 'default' => '0',
-                'limit' => 4,
+                'limit' => Phinx\Db\Adapter\MysqlAdapter::INT_TINY,
                 'null' => false,
             ])

または

 <?php
 use Migrations\AbstractMigration;
+use Phinx\Db\Adapter\MysqlAdapter;

-            ->addColumn('gender', 'tinyinteger', [
+            ->addColumn('gender', 'integer', [
                 'default' => '0',
-                'limit' => 4,
+                'limit' => MysqlAdapter::INT_TINY,
                 'null' => false,
             ])

他の type は?

他の type についても状況を確認。

  • ○: マイグレーションファイルを実行でき、type の変更もない。
  • △: マイグレーションファイルを実行できるが、type が変更される。
  • error: マイグレーションファイルを実行できない。
元の type 結果 作成された type
TINYBLOB BINARY(255)
BLOB BINARY(255)
MEDIUMBLOB error
LONGBLOB error
TINYTEXT TINYTEXT
TEXT TEXT
MEDIUMTEXT MEDIUMTEXT
LONGTEXT LONGTEXT
TINYINT error
SMALLINT error
MEDIUMINT INT(9)
INT INT
BIGINT BIGINT

blob は binary として扱われる。MEDIUMBLOB, LOGNBLOB の場合、以下のエラーになる。

SQLSTATE[42000]: Syntax error or access violation: 1074 Column length too big for column 'blob_long' (max = 255); use BLOB or TEXT instead

対応

-            ->addColumn('blob_long', 'binary', [
+            ->addColumn('blob_long', 'blob', [
                 'default' => null,
-                'limit' => 4294967295,
+                'limit' => Phinx\Db\Adapter\MysqlAdapter::BLOB_LONG,
                 'null' => true,

PostgreSQL の場合

SAMLLINT は、Exception: An invalid column typeが投げられる。
http://docs.phinx.org/en/latest/migrations.html#limit-option-and-postgresql

-            ->addColumn('gender', 'smallinteger', [
+            ->addColumn('gender', 'integer', [
                 'default' => null,
-                'limit' => 5,
+                'limit' => Phinx\Db\Adapter\PostgresAdapter::INT_SMALL,
                 'null' => false,

BIGINTはシンタックスエラー...

Exception: SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "("
LINE 1: ...users" ("id" BIGSERIAL NOT NULL, "big_int" BIGINT (20) NOT N...

対応

             ->addColumn('big_int', 'biginteger', [
                 'default' => null,
-                'limit' => 20,
+                'limit' => null,
                 'null' => false,
             ])

まとめ

多分、CakePHP 本体の対応が必要...

環境

  • CakePHP: 3.5.7
  • CakePHP Migrations: 1.7.1
  • Phinx: 0.8.1
  • PHP: 7.1.0
  • MySQL: 5.7.20
  • PostgreSQL: 10.1

明日は @keisukefunatsu さんです。