Silexだってdoctrine/migrations使う


## はじめに
Silexは、標準でマイグレーションツールを用意していないので、簡易的なツールを作ってしまったりしがちですが、`doctrine/migrations`はシンプルでクセがなく、かつ`Symfony\Component\Console\Command\Command`をベースにしたコマンドを用意しているので、Silexとの親和性も高くオススメです。

## 環境
- PHP 7.0.8
- Silex 2.0.2

プロジェクトは、[Silex-Skeleton](https://github.com/silexphp/Silex-Skeleton)をベースに作成していることを前提とします。
未確認ですが、上記以外のバージョンでも利用できると思われます。

## 導入手順
[公式サイト](http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html)にもドキュメントはありますが、それだけでは導入できないので、手順を記しておきます。

### インストール
composerからrequireします。

```
$ composer require doctrine/migrations
```

### コマンドの登録
`src/console.php`にて、下記のように、migrationコマンドを登録します。

```php
use Doctrine\DBAL\Migrations\Tools\Console\Command\DiffCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\ExecuteCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\LatestCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand;
use Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand;
use Symfony\Component\Console\Application;

$console = new Application('My Silex Application', 'n/a');

/** Doctrine\DBAL\Migrations */
$console->add(new DiffCommand());
$console->add(new ExecuteCommand());
$console->add(new GenerateCommand());
$console->add(new LatestCommand());
$console->add(new MigrateCommand());
$console->add(new StatusCommand());
$console->add(new VersionCommand());

return $console;
```

### 設定ファイルの作成
以下の2ファイルを作成します。

- migrations.yml
- migrations-db.php

### migrations.yml
migrations_namespace: マイグレーションクラスの名前空間を指定します。
table_name: マイグレーション情報を格納するテーブル名を指定します。
migrations_directory: マイグレーションファイルを格納しているディレクトリを指定します。

```yml
name: Doctrine Migrations
migrations_namespace: Namespace\To\Migrations
table_name: doctrine_migration_versions
migrations_directory: ./migrations
```

### migrations-db.php
データベースへの接続情報を下記のように記述します。

```php
return [
    'driver'    => 'pdo_mysql',
    'host'      => 'localhost',
    'dbname'    => 'example',
    'user'      => 'root',
    'password'  => '',
    'charset'   => 'utf8',
];
```

### コマンド一覧の表示
`bin/console list` でコマンドの一覧を表示します。

```bash
$ bin/console list

...(省略)...

Available commands:
  help                 Displays help for a command
  list                 Lists commands
 migrations
  migrations:diff      Generate a migration by comparing your current database to your mapping information.
  migrations:execute   Execute a single migration version up or down manually.
  migrations:generate  Generate a blank migration class.
  migrations:latest    Outputs the latest version number
  migrations:migrate   Execute a migration to a specified version or the latest available version.
  migrations:status    View the status of a set of migrations.
  migrations:version   Manually add and delete migration versions from the version table.
```

### マイグレーションクラスの作成
`migrations:generate` で空のマイグレーションクラスを作成します。

```bash
$ bin/console migrations:generate
Loading configuration from file: migrations.yml
Generated new migration class to "/path/to/migrations/Version20160803220846.php"
```

```php
<?php

namespace Namespace\To\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20160803220846 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs

    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs

    }
}
```

### upメソッドの実装
`AbstractMigration::addSql`で直接SQLを記述する、もしくは、`Schema`クラスの各メソッドを使用してデータベースを構築します。

- [AbstractMigration](https://github.com/doctrine/migrations/blob/master/lib/Doctrine/DBAL/Migrations/AbstractMigration.php)
  - addSql

    ```php
    public function up(Schema $schema)
    {
        $sql = 'CREATE TABLE `example` ( /* 省略 */ )';
        $this->addSql($sql);
    }
    ```

- [Schema](https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Schema/Schema.php)
  - getTable
  - createTable
  - renameTable
  - dropTable

    ```php
    public function up(Schema $schema)
    {
        $table = $schema->getTable('example');
        $table->addColumn('column', 'text', $options);
    }
    ```

### downメソッドの実装
upメソッドで加えた変更をもとに戻すコードをdownメソッドにて実装します。
実装方法については、upメソッドと違いはありませんので、説明は省略します。

### マイグレーションの実行
`migrations:migrate` でマイグレーションを実行します。

```bash
$ bin/console migrations:migrate
Loading configuration from file: migrations.yml
                                                           
                    Doctrine Migrations                    
                                                           

WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)
```

実行確認のメッセージが表示されますので、'y'を入力します。

```bash
WARNING! You are about to execute a database migration that could result in schema changes and data lost. Are you sure you wish to continue? (y/n)y
Migrating up to Version20160803220846 from 0

  ++ migrating Version20160803220846

...(省略)...

  ++ migrated (0.51s)

  ------------------------

  ++ finished in 0.58s
  ++ 1 migrations executed
  ++ 1 sql queries
```

## おわりに
類似のツールで[phpmig](https://github.com/davedevelopment/phpmig)がありますが、Silexの場合は、`doctrine/dbal`を標準でバンドルしているので、少ない追加コストで導入できるので、`doctrine/migrations`のほうがベターかと思います。