[CakePHP3 tips] コマンドラインから複数カラムにPrimary keyを設定した際の注意点

# はじめに
皆さんがガッツリめな記事を書く中、今日は簡単なtipsの共有です！！１

CakePHPの公式ドキュメントに記載されている [Bookmark tutorial](http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/intro.html)を試していてハマったのですが、タイトルの通り「コマンドラインから複数カラムにPrimary keyを設定した際の注意点」を紹介します。

# tl;dr
- コマンドラインからPrimary keyに設定されたカラムにはAutoIncrementの指定が自動でつく
- それが悪さをしてテーブル作成ができない場合があるが、実行時にエラーはでない
- AutoIncrementの指定を削除することで正しくマイグレーションが実行できる

# Cake3のマイグレーションを試してみる
チュートリアルの通りに進めていた中で、「せっかくだしSQLをそのまま実行するんじゃなくて、Migrationを使ってDBのschemaは管理しようかな」と思い試してみることにしました。

今回作成したいtableのschemaはこちら。

```
CREATE TABLE bookmarks_tags (
    bookmark_id INT NOT NULL,
    tag_id INT NOT NULL,
    PRIMARY KEY (bookmark_id, tag_id),
    FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
    FOREIGN KEY bookmark_key(bookmark_id) REFERENCES bookmarks(id)
);
```

調べると、Cake3は[Phinx](https://phinx.org/)というライブラリを使ってMigrationの機能を提供しているようです。

ドキュメントを読んで、コマンドラインから設定できる記述はなるべく設定してマイグレーションファイルの作成を試してみます。

```
$ bin/cake bake migration CreateBookmarksTags bookmark_id:integer:primary tag_id:integer:primary
```

上記コマンドの実行で下記ファイルが作成されました。

```/config/Migrations/2015********_create_bookmarks_tags.php
<?php 
use Migrations\AbstractMigration; 
 
class CreateBookmarksTags extends AbstractMigration 
{ 
 
    public $autoId = false; 
 
    public function change() 
    {   
        $table = $this->table('bookmarks_tags'); 
        $table->addColumn('bookmark_id', 'integer', [ 
            'autoIncrement' => true, 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addColumn('tag_id', 'integer', [ 
            'autoIncrement' => true, 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addPrimaryKey([ 
            'bookmark_id', 
            'tag_id', 
        ]); 
        $table->create(); 
    }   
}
```

作成したいテーブルには外部キーが設定されていますが、コマンドラインから設定することはできないようなので、その部分だけ追記して、下記の通りマイグレーションファイルを作成しました。

```/config/Migrations/2015********_create_bookmarks_tags.php
<?php 
use Migrations\AbstractMigration; 
 
class CreateBookmarksTags extends AbstractMigration 
{ 
 
    public $autoId = false; 
 
    public function change() 
    {   
        $table = $this->table('bookmarks_tags'); 
        $table->addColumn('bookmark_id', 'integer', [ 
            'autoIncrement' => true, 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addColumn('tag_id', 'integer', [ 
            'autoIncrement' => true, 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addPrimaryKey([ 
            'bookmark_id', 
            'tag_id', 
        ]); 
        $table->addForeignKey('tag_id', 'tags', 'id');  // ← 追記
        $table->addForeignKey('bookmark_id', 'bookmarks', 'id'); // ← 追記
        $table->create(); 
    }   
}
```

# マイグレーションを実行してもテーブルが作成されない
さて、さっそく実行してみましょう！下記コマンドで実行することができます。

```
$ bin/cake migrations migrate

Welcome to CakePHP v3.1.5 Console
---------------------------------------------------------------
App : src
Path: /Users/fortkle/Private/bookmarker/src/
PHP : 5.6.16
---------------------------------------------------------------
using migration path /Users/fortkle/Private/bookmarker/config/Migrations
using environment default
using adapter sqlite
using database /Users/fortkle/Private/bookmarker/database/production.sqlite

 == 20151220122251 CreateBookmarksTags: migrating
 == 20151220122251 CreateBookmarksTags: migrated 0.0036s

All Done. Took 0.0048s
```

もろもろ実行されて最後に「All Done」と成功を匂わせるメッセージを出しています。
本当にテーブルが作成されているか確認してみましょう（今回は楽をするためにSQLiteを使っています）。

```
sqlite> .tables
phinxlog
```

あれ？テーブルが作成されていません。「All Done」とは何だったのでしょうか...

migrationのstatusを確認します。

```
$ bin/cake migrations status

Welcome to CakePHP v3.1.5 Console
---------------------------------------------------------------
App : src
Path: /Users/fortkle/Private/bookmarker/src/
PHP : 5.6.16
---------------------------------------------------------------
using migration path /Users/fortkle/Private/bookmarker/config/Migrations
using environment default

 Status  Migration ID    Migration Name 
-----------------------------------------
     up  20151220122251  CreateBookmarksTags
```

「Status up」ということは「マイグレーション実行済み」ということでこちらも実態と異なっています...。

# 原因は「AUTO INCREMENT」
結論から言うと、テーブルが作成されていない理由は「AUTO INCREMENTが自動設定されていたから」でした。

コマンドラインからprimary keyを設定したカラムには自動で `'autoIncrement' => true` が記述されていたため、上手くマイグレーションが実行されなかったということです。

下記の通り bookmark_id と tag_id に設定されていたautoIncrementの記述を削除してマイグレーションファイルを保存し、phinxlogから実行済みレコードを削除して再度マイグレーションすることでテーブルが作成できました。

```/config/Migrations/2015********_create_bookmarks_tags.php
<?php 
use Migrations\AbstractMigration; 
 
class CreateBookmarksTags extends AbstractMigration 
{ 
 
    public $autoId = false; 
 
    public function change() 
    {   
        $table = $this->table('bookmarks_tags'); 
        $table->addColumn('bookmark_id', 'integer', [ 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addColumn('tag_id', 'integer', [ 
            'default' => null, 
            'limit' => 11, 
            'null' => false, 
        ]); 
        $table->addPrimaryKey([ 
            'bookmark_id', 
            'tag_id', 
        ]); 
        $table->addForeignKey('tag_id', 'tags', 'id');
        $table->addForeignKey('bookmark_id', 'bookmarks', 'id');
        $table->create(); 
    }   
}
```


以上、しょーもないけどハマると結構時間が取られる系問題のtipsでした！