導入のための留意点
筆者は、CakePHP3での採用と他のフレームワークでも非依存で利用できるからという理由で導入をした。
しかしCakeDCのmigrations pluginと同じ考え方なんだろうという先入観があったために、かえって理解しづらい点があったので、そういう方は次の点を念頭に置くと悩みが少ない(かもしれない)。
- 既にあるDBをリバースエンジニアリングする機能はない。
- CakePHPのschema.phpに相当する概念がない。
- DDLをSQLではなく、phpのコードで書けるのが利点…と捉えた方がいい。
- マイグレーションをPhinxの管理下に置くということは、何もない状況からマイグレーションできるようにすべきだから、既存のDDLがある場合は書き換える必要がある。
- SQLを書けるメソッド(executeやquery)があるので、ヒアドキュメントを使う方法はある。
- 既にDBを構成している環境では使いにくい。
- Phinxでは専用の履歴テーブル(デフォルトでPhinxlog)を作って、マイグレーションがどこまで適用しているかのステータスを保持する。
- 既にDB展開済の場合は、Phinxが持つステータス状況と実態が合わずに、問題が起こりうる。
- それを回避するには、マイグレーションのup/downメソッドにテーブルやフィールド(コラム)の実在確認の処理を書くか、初回を空っぽにして、2回目からまじめに書く。(ただしDDLは別提供)
- または、初回マイグレーションだけぶっ放し、2回目からまじめに書く。
導入
既にリポジトリに入っており、利用者としてセットアップしたい人はインストールの項から参照のこと。
展開ディレクトリの作成
Composerを使うので、他のライブラリーをComposerでインストールしている場合は、同じvendorsに展開される。
もし独立した環境にしたい場合は、別にディレクトリを作り、その中で展開する。
gitignoreの設置
お好みでgitignoreを設置する。
composerでインストールできるものはリポジトリ管理に入れず、自分たちが書いたものだけを入れるというセオリーがあるので、全部をコミットするのは推奨しない。
$ vi .gitignore
vendor
Phinx.yml
composer
composer.jsonを配置
$ vi composer.json
{
"require":{
"robmorgan/Phinx": "*"
}
}
もし、チームで、環境にcomposerをインストールしない場合は、composer.pharをプロジェクトに配置してコミットしておく。
$ curl -s http://getcomposer.org/installer | php
インストール
環境にcomposerをインストール済の場合は
$ composer install
composerをインストールされていない場合は、composer.pharを使う。
$ php composer.phar install
Phinxが使用できる状態になったので、環境定義(Phinx.yml)を生成し、DB情報を編集する。
$ ./vendor/bin/Phinx init
$ vi Phinx.yml
environmentsのところに、production, development, testingの3つの環境定義があるが、デフォルトはdevelopmentなので、複数の環境を使い分けない場合は、developmentのところだけ書き換える。
development:
adapter: mysql
host: localhost
name: (データベース名)
user: (ログインID)
pass: (パスワード)
port: 3306
charset: utf8
マイグレーション処理の流れ
詳細はそれぞれ後述ので、概要として流れを解説する。
-
マイグレーション定義ファイルを生成する
ファイルを作って、定義が書ける準備をする。 -
マイグレーション定義ファイルに処理を書く。
定義ファイルの中にchange, up, downのメソッドが生成されるので、これに記述を行う。 -
マイグレーションを実行する。
これによりDBに変更が実行され、Phinxlogテーブルが作成され、どこまでマイグレーションされているかを記録する。
以降、変更を加えるごとに1〜3を実行する。gitにおけるプル→コミットのように、3→1→2→3となる。
マイグレーションを反映させるには、3だけを実行する。
留意すべきは、リバースしないのでDBを直接編集せず、定義ファイルに記述し、それを実行することでDBに変更を与えること。
1.マイグレーション定義ファイルの生成
まず空の定義ファイルを作り、そこに処理を書いてマイグレーション定義が完成する。
次のコマンドで、定義ファイルが作成される。定義ファイルを格納するフォルダ(デフォルトでは ./migrations)が存在していない場合は、自動的に作成される。
$ ./vendor/bin/Phinx create (定義名)
定義名とは、マイグレーション定義ファイルに付ける名前であり、その中で定義されるクラス名になる。
公式ドキュメントでは「MyNewMigration」という名前になっているが、何をしたのか分かる名前を付ける方がよい。(statusを参照)
定義名は、CamelCaseでなければならない。
「initial」はエラーになり、「Initial」はOK。
これで、./migrations/20150614151105_initial.php という日付+定義名でファイルが作成される。
ちなみに、この時点でPhinx.ymlを設定していなくてもエラーにならないことからも、マイグレーションの実行以外ではDBへのアクセスはない。
2.マイグレーションファイルに処理を書く
作成された定義ファイルを開く。
$ vi ./migrations/20150614151105_initial.php (例)
内容としては、change, up, downの3つのメソッドがあり、changeは最初コメントアウトされている(後述の通り、up/downと排他的に動作するため)。
メソッド | 処理
---+---
up | マイグレーションするときに実行される
down | ロールバックするときに実行される
change | マイグレーションするときに実行されるが、ロールバックする場合も、逆処理を行う。なお、このメソッドが有効(宣言されている状態)の場合、up/downは実行されない。
逆処理とは、addColumnの場合はremoveColumnが実行されることを意味する。当然全てが逆処理できるわけではなく、対応しているのは下記の通り。
changeメソッド内のコマンド(migrateで実行) | rollbackで実行されるコマンド
-------------+---------------
createTable | dropTable
renameTable | renameTable(引数逆)
addColumn | removeColumn
renameColumn | renameColumn(引数逆)
addIndex | removeIndex
addForeignKey | dropForeignKey
これ以外の処理を行う場合は、up/downでそれぞれ処理を書く方がよい。
テーブル操作
$table = $this->table(‘テーブル名’);
ここで代入した$tableに対して、処理を行う。
テーブルの追加
addColumnとコラム追加をしてから、create()メソッドを呼ぶ。
addColumnについては後述
$table->addColumn('name', 'string', array('limit' => 100)
->addColumn('age', 'integer')
->create();
create/updateとsave
createはテーブル生成を明示するものだが、公式ドキュメントではcreateではなく、saveメソッドを呼ぶと書かれている。
saveは、createまたはupdateになるので、基本的にup/downメソッドに記述する場合はsaveでよい。
しかしchangeメソッドで定義する場合は、公式ドキュメントにも書かれている通り、createまたはupdateを明示しなければならないと書かれている。理由はrollbackするときにコラムを消すのか、droptableするのかが自動的には判断できないため。
そのため、このドキュメントではcreate/updateを使用している。
テーブルの削除
$this->dropTable('users');
列操作
列の追加
$table->addColumn('列名', '型' , array(オプション))
->addColumn(…繰り返し…)
->save();
列名
フィールド名
型
型には次のものが使用できる。…と言いたいところだが、(お察し下さい)なので、公式ドキュメント参照。
なおstringは、limitオプションを付けない限り、デフォルトではvarchar(255)。
オプション
(お察し下さい)なので、公式ドキュメント参照。
列の削除
$table->removeColumn('列名')
->update()
列名の変更
$table->renameColumn('変更前', '変更後');
インデックス
addColumnなどと組み合わせて定義する。
$table->addIndex(array('列名1', '列名n'))
->update()
既にテーブルが存在しているかどうか
$exists = $this->hasTable('users');
if ($exists) {
〜
}
SQLの実行
executeとqueryがあるが、返値に違いがある。
//影響を及ぼしたレコード数が返値
$count = $this->execute('DELETE FROM users');
//実行した結果が返値
$rows = $this->query('SELECT * FROM users');
既に作成済みのDDLをぶっ放す。
public function up()
{
$query = <<<EOQ
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(255) default NULL,
`age` integer,
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`)
)AUTO_INCREMENT=1 ;
EOQ;
$this->execute($query);
}
public function down()
{
$this->dropTable('users');
}
idの自動生成を抑制する
Phinxは、id列を自動的に追加する。自分でid列の仕様を指定したり、primary keyを変更したい場合は邪魔になる。その場合は、下記のようにテーブル指定時にオプションで指定する。
$table = $this->table('statuses',
[
'id' => false,
'primary_key' => ['id']
]);
$table->addColumn('id', 'char', ['limit' => 36])
->addColumn('name', 'char', ['limit' => 255])
->addColumn('model', 'string', ['limit' => 128])
->create();
3.マイグレーションを実行する
migrate
マイグレーションの実行。マイグレーション定義ファイルのupメソッドまたはchangeメソッドを実行する。(changeメソッドがある場合は、upメソッドは無視される)
後述の-tオプションなしでは、最新まで一括でマイグレーションする。
$ ./vendor/bin/Phinx migrate
rollback
1つずつ戻す。downメソッドまたはchangeメソッドの逆処理を実行する。(up同様changeメソッドがある場合はdownメソッドは無視される。)
$ ./vendor/bin/Phinx rollback
ターゲットを指定する
ターゲットを指定したい場合は、-tオプションを付け、マイグレーションIDを指定する。
例)20150614154730_my_migration.phpの場合
$ ./vendor/bin/Phinx migrate -t 20150614154730
status
全てのマイグレーション一覧を表示し、かつ現在のマイグレーション適用状況を表示する。
$ ./vendor/bin/Phinx status
Status Migration ID Migration Name
-----------------------------------------
up 20150614070924 InitialTable
up 20150615021023 Users
down 20150615111810 Logs
down 20150615112743 Contents
この場合、Usersまでは適用されているが、Logsから適用されていないことを示している。