はじめに
皆さんがガッツリめな記事を書く中、今日は簡単なtipsの共有です!!1
CakePHPの公式ドキュメントに記載されている Bookmark tutorialを試していてハマったのですが、タイトルの通り「コマンドラインから複数カラムに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というライブラリを使ってMigrationの機能を提供しているようです。
ドキュメントを読んで、コマンドラインから設定できる記述はなるべく設定してマイグレーションファイルの作成を試してみます。
$ bin/cake bake migration CreateBookmarksTags bookmark_id:integer:primary tag_id:integer:primary
上記コマンドの実行で下記ファイルが作成されました。
<?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();
}
}
作成したいテーブルには外部キーが設定されていますが、コマンドラインから設定することはできないようなので、その部分だけ追記して、下記の通りマイグレーションファイルを作成しました。
<?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から実行済みレコードを削除して再度マイグレーションすることでテーブルが作成できました。
<?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でした!