こんにちは。リスペクトの木村です。
以前に書いた記事、「Vagrant環境で実現するお手軽DBマイグレーション」の中で、「Flyway」というJavaで動作するマイグレーションツールをご紹介しました。
Flywayは言語やアプリケーションを問わず使えたり、生のSQLクエリで記述するので汎用性が高い点が良かったのですが、別途Javaが必要であるとか、up(マイグレーション)はできてもdown(ロールバック)が出来ないという難点がありました。
サイトのリニューアルにあたりマイグレーション周りを整備する必要があったため、難点が解消できるツールを探した所、「Phinx」というマイグレーションツールがありました。
使ってみた所非常に良い感じでしたので、今回はそちらをご紹介します。
今回の環境
- CentOS 7
- PHP 5.6.14
- MySQL 5.7.9
- Phinx 0.4.6
What’s Phinx?
PHPで書かれたPHP向けのマイグレーションツールです。
PHP 5.3.2以降が動いている環境(Phinx 0.4.6時点)であれば簡単に使い始める事ができます。
Flywayや他のマイグレーションツールと比較してみた特徴はこんな感じです。
- インストールや設定が簡単
- フレームワーク依存ではない
- 軽い
- ORM/SQL文の両方の記述に対応
- 後述しますが、ORMを使った方がより多くの恩恵を受けられます
- MySQL/PostgreSQL/SQLite/SQL Serverに対応
ちなみに、CakePHP3のマイグレーションにも採用されています。
(という事は、CakePHP2系のmigration pluginとは互換性が無いという事になります。トホホ。)
導入方法
お手元のcomposer.jsonに、次のようにrequire内に追加してinstallを実行するだけです。
(*で設定していますが、バージョンなどは環境に合わせて下さい。)
{
"require":{
"robmorgan/phinx": "*"
}
}
composerコマンド(もしくはcomposer.phar)からでも追加できます。
$ composer require robmorgan/phinx
インストールすると、vendor/bin/phinx(vendor/bin/phinx.bat) に実行スクリプトが、vendor/robmorgan/phinx 以下にライブラリがインストールされます。
設定
まずはvendor/bin/phinx initで初期化を行い、phinx.ymlという設定ファイルをを作成します。
phinx.ymlにはデータベース接続設定などが保存されます。デフォルトではYAMLで生成されますが、phinx.jsonやphinx.phpというファイルを用意する事でJSONやPHPを生成することもできます。
生成されるファイルの中身はこんな感じです。
paths:
migrations: %%PHINX_CONFIG_DIR%%/migrations
environments:
default_migration_table: phinxlog
default_database: development
production:
adapter: mysql
host: localhost
name: production_db
user: root
pass: ''
port: 3306
charset: utf8
development:
adapter: mysql
host: localhost
name: development_db
user: root
pass: ''
port: 3306
charset: utf8
testing:
adapter: mysql
host: localhost
name: testing_db
user: root
pass: ''
port: 3306
charset: utf8
必要に応じ、このファイルの設定内容を手動で変更していきます。
paths:migrations:はマイグレーションファイルの保存先を指定します。
デフォルトはphinx.ymlのあるディレクトリ(%%PHINX_CONFIG_DIR%%)のmigrationsディレクトリを指しています。
マイグレーションファイルの作成時にディレクトリが存在しない場合は作成してくれます。
environments:default_migration_tableはマイグレーション情報を管理するテーブル名を設定できます。基本的にはデフォルトで良いのですが、命名ルールにポリシーがある場合など必要に応じて変更しておきます。
ちなみに、このテーブルは初回マイグレーション時に勝手に作成されます。
お次のenvironments:default_databaseは環境を指定しない場合のデフォルトで使用する環境設定名です。
引数でその設定を使用するか指定できますので、変更する必要はありません。
environments:productionやenvironments:development・environments:testingは環境毎の接続設定を記述します。
この3つしか使えない訳では無いので、設定を追加したり減らしたりする事も可能です。
他の設定についてはドキュメントを確認してください。
ソケット接続や接続先DBMSに合わせた設定もそこそこ細かく行えるようです。
マイグレーションの作成
テーブル作成のマイグレーション
準備が整ったので、実際にマイグレーションファイルを作成します。
作成はvendor/bin/phinx create マイグレーション名で、マイグレーション名はキャメルケースで指定します。
今回はmembersテーブルを作成する、という事にするので、AddMembersTableという名前にしました。
$ vendor/bin/phinx create AddMembersTable
ちなみに、マイグレーション名がキャメルケースではなかった場合は、下記のようにExceptionとエラーメッセージが表示されます。
[vagrant@localhost html]$ vendor/bin/phinx create addMembersTable Phinx by Rob Morgan - https://phinx.org. version 0.4.6 using config file ./phinx.yml using config parser yaml using migration path /var/www/html/migrations [InvalidArgumentException] The migration class name "addMembersTable" is invalid. Please use CamelCase format.
コマンドを実行するとmigrationsディレクトリの中に日付と時間_マイグレーション名.phpという命名規則で、空のマイグレーションファイルが作成されます。
中身は以下のような感じです。
<?php
use PhinxMigrationAbstractMigration;
class AddMembersTable extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* renameColumn
* addIndex
* addForeignKey
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
}
}
作成直後はchange()メソッドしかありませんので、基本的にはこの中に記述します。
今回はmembersテーブルを作成するので、こんなようになります。
public function change()
{
$table = $this->table('members');
$table->addColumn('name', 'string')
->addColumn('age', 'integer')
->addColumn('created', 'datetime')
->addColumn('modified', 'datetime')
->addColumn('deleted', 'boolean')
->create();
}
$this->table()でテーブル名を指定してインスタンスを取得し、それに対してaddColumnやaddIndexをして最後にcreate()でテーブルを作成します。
addColumnだけでは作成してくれないので注意が必要です。
addColumnの関数定義はこのようになっています。
public function addColumn($columnName, $type = null, $options = array())
$columnNameがカラム名、$typeはカラムの種類、$optionsはオプション(サイズやデフォルト値、NULLの許可不許可など)です。
カラムのタイプについては後ほど説明します。また、オプションについては色々あるため、ドキュメントを参照下さい。
また、主キーのカラムは「id」という名前で勝手に作成してくれます。(int(11) AUTO INCREMENT)
そのため、addColumnでid名のカラムを作成しようとするとエラーになるので注意が必要です。
idが不要な場合は、$this->table()の第二引数に下記のようなオプションを渡します。
$this->table('members', array('id' => false));
また、主キーを「id」以外の名前にする場合は、上記のfalseを渡している部分を、設定したい名前を渡すようにします。
「id」と同じく指定した名前でカラムを作成してくれますので、addColumnは不要です。
$this->table('members', array('id' => ‘member_id’));
changeメソッド内でのテーブル操作は次の関数のみ利用可能です。
(他の関数を利用すると、IrreversibleMigrationExceptionの例外がdown時に発生します。)
これらを利用して記述する事で、up時やdown時にマイグレーションの内容を自動的に調整して実行します。
- createTable
- renameTable
- addColumn
- renameColumn
- addIndex
- addForeignKey
例えば、addColumnを使用した場合は、up時にカラムを追加し、down時はカラムを削除する、という動きをしてくれます。
カラム操作系ですとaddColumnやrenameColumnの他に、removeColumnというのもあるのですが、これを利用する場合はchangeメソッドが利用できないため、upやdownへ必要な処理を記述する事になります。
insertでデータを追加する時や、queryを用いて直接SQLクエリを実行する場合も同様に、upやdownへ必要な処理を記述する必要があります。
カラム追加のマイグレーション
お次はカラムを追加してみます。
UUID用のカラムを追加する、という事で進めます。マイグレーションファイルの名前は、ベタベタにAddUuidColumnAtMembersTableに。
$ vendor/bin/phinx create AddUuidColumnAtMembersTable
中身はこうなります。テーブル作成時とあまり変わらない感じです。
public function change()
{
$table = $this->table('members');
$table->addColumn('uuid', 'uuid')
->save();
}
最後のcreate()がsave()になってますが、save()は保存用のメソッドです。テーブルの有無をチェックして、無い場合はテーブルを作成してくれます。
となると、先ほどのテーブル作成時もcreate()ではなくsave()で良いのですが、ここでは分かりやすくするため使い分ける事にします。
カラムの種類
カラムは下記のようなタイプに対応しています。
- biginteger
- binary
- boolean
- date
- datetime
- decimal
- float
- integer
- string
- text
- time
- timestamp
- uuid
MySQLの場合、上記に加えてenumとsetにも対応しています。
特にオプションを指定しない場合の、MySQLとの対応表は下記のような感じです。
| Phinx | MySQL |
|---|---|
| biginteger | bigint(20) NOT NULL |
| binary | blob NOT NULL |
| boolean | tinyint(1) NOT NULL |
| date | date NOT NULL |
| datetime | datetime NOT NULL |
| decimal | decimal(10,0) NOT NULL |
| float | float NOT NULL |
| integer | int(11) NOT NULL |
| string | var_char(255) NOT NULL |
| text | text NOT NULL |
| time | time NOT NULL |
| timestamp | timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
| uuid | char(36) NOT NULL |
| enum | enum(オプションの「values」で指定した内容) NOT NULL |
| set | set(オプションの「values」で指定した内容) NOT NULL |
migrate / rollback
記述もできた所で、マイグレーションを実行します。
phinx migrateで実行しますが、そのままですとenvironments:default_databaseの環境で実行されるため、-eオプションで環境を指定します。
development環境に対して実行する場合は下記のような感じです。
$ vendor/bin/phinx migrate -e development
実行するとこんなログが流れます。
[vagrant@localhost html]$ vendor/bin/phinx migrate -e development Phinx by Rob Morgan - https://phinx.org. version 0.4.6 using config file ./phinx.yml using config parser yaml using migration path /var/www/html/migrations using environment development using adapter mysql using database development_db == 20151023110916 AddMembersTable: migrating == 20151023110916 AddMembersTable: migrated 0.0079s == 20151023122445 AddUuidColumnAtMembersTable: migrating == 20151023122445 AddUuidColumnAtMembersTable: migrated 0.0077s All Done. Took 0.0198s
確認すると、確かにテーブルが作成されています。
mysql> show tables; +--------------------------+ | Tables_in_development_db | +--------------------------+ | members | | phinxlog | +--------------------------+ 2 rows in set (0.00 sec) mysql> show columns from members; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | NULL | | | age | int(11) | NO | | NULL | | | created | datetime | NO | | NULL | | | modified | datetime | NO | | NULL | | | deleted | tinyint(1) | NO | | NULL | | | uuid | char(36) | NO | | NULL | | +----------+--------------+------+-----+---------+----------------+ 7 rows in set (0.00 sec)
ちなみに、phinxlogはマイグレーション情報管理のテーブルです。
ロールバックは下記のように実行します。
$ vendor/bin/phinx rollback -e development
実行時のログはこんな感じで、AddUuidColumnAtMembersTableが戻ります。
[vagrant@localhost html]$ vendor/bin/phinx rollback -e development Phinx by Rob Morgan - https://phinx.org. version 0.4.6 using config file ./phinx.yml using config parser yaml using migration path /var/www/html/migrations using environment development using adapter mysql using database development_db == 20151023122445 AddUuidColumnAtMembersTable: reverting == 20151023122445 AddUuidColumnAtMembersTable: reverted 0.0114s All Done. Took 0.0152s
実行後に確認すると、UUIDカラムが無くなりました。
mysql> show columns from members; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | NULL | | | age | int(11) | NO | | NULL | | | created | datetime | NO | | NULL | | | modified | datetime | NO | | NULL | | | deleted | tinyint(1) | NO | | NULL | | +----------+--------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)
もう一回実行すると・・・
[vagrant@localhost html]$ vendor/bin/phinx rollback -e development Phinx by Rob Morgan - https://phinx.org. version 0.4.6 using config file ./phinx.yml using config parser yaml using migration path /var/www/html/migrations using environment development using adapter mysql using database development_db == 20151023110916 AddMembersTable: reverting == 20151023110916 AddMembersTable: reverted 0.0067s All Done. Took 0.0104s
テーブルが無くなりました。
mysql> show tables; +--------------------------+ | Tables_in_development_db | +--------------------------+ | phinxlog | +--------------------------+ 1 row in set (0.00 sec)
migrate/rollback共に-tオプションで対象のバージョン(マイグレーションファイル名先頭の日付の部分)を指定できます。
また、rollbackのみ-t 0で全てのバージョンをロールバックして初期の状態に戻します。
status
statusコマンドを使用する事で、現在のマイグレーションの状態を確認する事ができます。
[vagrant@localhost html]$ vendor/bin/phinx status -e development Phinx by Rob Morgan - https://phinx.org. version 0.4.6 using config file ./phinx.yml using config parser yaml using migration path /var/www/html/migrations using environment development Status Migration ID Migration Name ----------------------------------------- down 20151023110916 AddMembersTable down 20151023122445 AddUuidColumnAtMembersTable
全てロールバックした後ですので、「Status」が全てdownになっています。
再度マイグレーションすると、全てupになっています。
[vagrant@localhost html]$ vendor/bin/phinx status -e development
Phinx by Rob Morgan - https://phinx.org. version 0.4.6
using config file ./phinx.yml
using config parser yaml
using migration path /var/www/html/migrations
using environment development
Status Migration ID Migration Name
-----------------------------------------
up 20151023110916 AddMembersTable
up 20151023122445 AddUuidColumnAtMembersTable
まとめ
ここまでPhinxのご紹介でした。
コマンド数も少なく覚えやすいですし、自動判定のおかげでマイグレーションを書く時間が少なくなりましたので良い感じに運用できています。
大体のフレームワークにはマイグレーションが標準機能やプラグインとして提供されていますので出番は少ないかもしれませんが、「あまり合わないので代替えのものを使いたい」という時や「オレオレフレームワークやベタで書いていたりして、そもそも付いてない」という時に選択肢の一つに入れてみてはいかがでしょうか。
Composerで入れられますので、どんな環境でもスムーズに導入できるはずです。
現場からは以上です。