PHP
Phinx

Phinx導入ガイド


導入のための留意点

筆者は、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


マイグレーション処理の流れ

詳細はそれぞれ後述ので、概要として流れを解説する。


  1. マイグレーション定義ファイルを生成する

    ファイルを作って、定義が書ける準備をする。


  2. マイグレーション定義ファイルに処理を書く。

    定義ファイルの中にchange, up, downのメソッドが生成されるので、これに記述を行う。


  3. マイグレーションを実行する。

    これにより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から適用されていないことを示している。