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

これは [CakePHP Advent Calendar 2017](https://qiita.com/advent-calendar/2017/cakephp) の第14日目の記事です。
CakePHP の [Slackチャンネル](https://qiita.com/chinpei215/items/3c116171c5308365c314) で[話題](https://cakesf.slack.com/archives/C1FT02VQA/p1512625191000068)に上がっていたので前倒しで公開します。

## 三行

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




## 発端


```sql
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

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

または

```diff
 <?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


対応

```diff
-            ->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

```diff
-            ->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...  


対応

```diff
             ->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 さんです。