PHP製マイグレーションツール Phinx の動作検証

## はじめに
以前 [DBマイグレーションツールを比較した phpmig, migrate, goose](https://qiita.com/hypermkt/items/e48ca78f626faf23b41a) の記事を書きましたが、どのツールも満足がいかずツール選定は保留状態のままでした。しかし最近PHP製のPhinxというツールが良いという情報を見かけ、ドキュメントを見た所、かなり良さそうだったので検証したいと思います。

## Phinx とは

[Phinx](https://github.com/cakephp/phinx) はPHP製のデータベースマイグレーションライブラリです。公式サイトとドキュメントを読んで受けたメリット・デメリットは以下でした。

### メリット
* CakePHP公式マイグレーションツールでありながら、独立したコマンドラインツールとして利用可能
* インストールが簡単
* 簡単なコマンドライン操作
* Star数 3200超え
* 充実したドキュメント

### デメリット
* 要学習コスト(そこまで難しくはないと思います

## マイグレーションツールに求めるもの
個人的にマイグレーションツールに求める点は以下です。

* 充実したドキュメント
    * チームに導入することを考えた場合にドキュメントは必要です。
* 継続的な開発
* 簡単なコマンドライン操作
    * CIや開発環境で利用したいので簡単に利用できるものが良いです。
* 【重要】特定バージョンのマイグレーションの実行
    * 本番サーバーでの実行したら最初からCREATE文が実行されたら困ります。

これらの点が満たされるか見ていきましょう

## 検証環境
* macOS Sierra
* PHP 7.1.1 + PDO_MYSQL
    * `PDO_MYSQL` が無いと `You need to enable the PDO_Mysql extension for Phinx to run properly.` が発生して利用できません
* MySQL 5.7
    * マイグレーション先のデータベース・ユーザーは作成済み

## Phinx を使ってみよう

### インストール
Composer で簡単にインストールできた。

```shell-session
$ composer require robmorgan/phinx
```

```shell-session
$ vendor/bin/phinx
Phinx by CakePHP - https://phinx.org. 0.8.1

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  breakpoint   Manage breakpoints
  create       Create a new migration
  help         Displays help for a command
  init         Initialize the application for Phinx
  list         Lists commands
  migrate      Migrate the database
  rollback     Rollback the last or to a specific migration
  status       Show migration status
  test         Verify the configuration file
 seed
  seed:create  Create a new database seeder
  seed:run     Run database seeders
```

### 初期設定

`init` コマンドで初期化すると、データベース接続設定ファイルの `phinx.yml` が生成されます。

```shell-session
$ vendor/bin/phinx init
Phinx by CakePHP - https://phinx.org. 0.8.1

created ./phinx.yml
```

今回はローカル環境のMySQLを利用して検証します。developmentの項目を各自の環境に合わせて変更してください。

```shell-session
    development:
        adapter: mysql
        host: 127.0.0.1
        name: development
        user: root
        pass: ''
        port: 3306
        charset: utf8
```

これはドキュメントに記載がないのですが、事前に以下ディレクトリを作成しておいてください。

```shell-session
$ mkdir -p db/migrations
$ mkdir -p db/seeds
```

そうしないと以下エラーが発生します。

```shell-session
  [Exception]
  You probably used curly braces to define migration path in your Phinx configuration file, but no directories have been matched using this pattern. You need to create a migration directory manually.
```

### Postsテーブルを作成する

`create` コマンドでマイグレーションファイルを作成します。

```shell-session
$ vendor/bin/phinx create AddPostsTable
#{省略}
created db/migrations/20171114150219_add_posts_table.php
```

今回はCakePHP3のクイックスタートガイドにある[CMSチュートリアル](https://book.cakephp.org/3.0/ja/quickstart.html#cms)のテーブルを作成してきます。以下の `users` テーブルを Phinx のPHP APIに書き直すと

```sql
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
```

以下になります。 

```php
public function change()
{
    $table = $this->table('users');
    $table->addColumn('email', 'string', ['null' => false])
        ->addColumn('password', 'string', ['null' => false])
        ->addColumn('created', 'datetime')
        ->addColumn('modified', 'datetime')
        ->create();
}
```

以下コマンドでdevelopment 環境に対してマイグレーションを実行できます。

```shell-session
$ vendor/bin/phinx migrate -e development
```

生のSQLでも記述できます。

```php
public function change()
{
    $this->execute("
        CREATE TABLE users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            email VARCHAR(255) NOT NULL,
            password VARCHAR(255) NOT NULL,
            created DATETIME,
            modified DATETIME
        );
    ");
}
```

Phinx APIを利用することで簡素に記述できるようになり、メソッドによってはロールバック対応もしているので、理由がない限りはPhinx APIを使うのが良いと思います。ただし運用中のシステムにPhinxを導入する場合で既存のスキーマをテキストファイルなどで管理している場合は、初回のみ生のSQLで導入するのも有りです。

### バージョンナンバーを指定して実行

`-t, --target=TARGET                The version number to migrate to`

を利用することで出来ます。

```shell-session
$ vendor/bin/phinx migrate -e development -t 20171114154718
```

### dryrun実行
`-x, --dry-run                      Dump query to standard output instead of executing it`

を利用することで、実行されるSQL文を確認することができます。

```shell-session
$ vendor/bin/phinx rollback -e development --dry-run
Phinx by CakePHP - https://phinx.org. 0.8.1
#{省略}

 == 20171114150219 AddUsersTable: reverting
START TRANSACTION
DROP TABLE `users`
COMMIT
DELETE FROM phinxlog WHERE `version` = '20171114150219'
 == 20171114150219 AddUsersTable: reverted 0.0014s
```

dryrunモードがあると、事前確認ができるので安心ですね。

### まとめ

各ツールを3点(1:悪い/難しい 2:普通 3:良い/簡単）で評価してみます。

||Phinx|
|---|---|
|ドキュメントの充実性|3|
|インストール難易度|3|
|学習コスト|2|
|機能性|3|
|将来性|3|
|合計|14|

[以前](https://qiita.com/hypermkt/items/e48ca78f626faf23b41a)検証したphpmig, migrate, goose と比較しても Phinx の方が実用的な印象でした。以下に検証して良かった点、悪かった点、他ツールとの比較をまとめます。

### 良かった点
* マイグレーションツールとして完成度が高い。
* ドキュメントが充実しているので、たいていの使い方はドキュメントを見ればわかる。
* ２大PHPフレームワークのCakePHP3に採用されている安心感と将来性
* 個人的に一番欲しかったバージョンナンバー指定実行があるので、運用中のシステムでも本番環境で利用できる
* Phinx PHP APIの可読性が高い
* dryrunモードがあるので安心

### 悪かった点
* 最初だけPhinx PHP APIの勉強が必要

最後に個人的な感想ですが、筆者がPHPerなのでPHPで利用できるのもありがたいです。やっと満足のいくマイグレーションツールが見つかったので、Phinx でチームへの導入を検討したいと思います。

## 参考
* [Phinx](https://phinx.org/)