Symfony2のDoctrineMigrationsBundleで簡単マイグレーション

2013年11月14日

symfony-logo

Symfony2 の DoctrineMigrationsBundle を使ってデータベースのマイグレーションを行う方法を整理しました。

マイグレーションする方法、変更を元に戻す方法など必要最低限の使い方を紹介します。マイグレーションを導入すると複数の環境に変更を反映することが容易になるので、Symfony2 を使っているならぜひ導入を検討してみてください。

これに加え、capifony でデプロイを自動化すると鬼に金棒です。こちらも併せてどうぞ。

capifonyでSymfony2アプリをコマンド一発デプロイ

動作確認環境

  • Mac OS X Mountain Lion
  • PHP 5.4
  • MySQL 5.6
  • Symfony 2.3

目次

  1. Symfony2 に DoctrineMigrationsBundle をインストールする
  2. マイグレーションを初期化する
  3. マイグレーションファイルを作成する
  4. マイグレーション実行
  5. 変更をもとに戻す
  6. マイグレーションが壊れてしまった場合は
  7. その他の使い方

Symfony2 に DoctrineMigrationsBundle をインストールする

composer.json に以下を追加します。packagist に dev-master しか登録されていないのが少し怖いです。

{
    ...
    "require": {
        ...
        "doctrine/doctrine-migrations-bundle": "dev-master"
        ...
    }
    ...
}

composer update コマンドを実行します。

$ composer update

app/AppKernel.php に以下を追加します。

public function registerBundles()
{
    $bundles = array(
        //...
        new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
        //...
    );
}

app/console list コマンドを実行して以下のようにコマンド一覧が表示されればインストール成功です。

$ php app/console list | grep migration
  doctrine:migrations:diff
  doctrine:migrations:execute
  doctrine:migrations:generate
  doctrine:migrations:migrate
  doctrine:migrations:status
  doctrine:migrations:version

マイグレーションを初期化する

app/console doctrine:migrations:status コマンドを実行してマイグレーションを初期化します。

$ php app/console doctrine:migrations:status
 == Configuration
...
    >> Current Version:                                    0
    >> Latest Version:                                     0
    >> Executed Migrations:                                0
    >> Executed Unavailable Migrations:                    0
    >> Available Migrations:                               0
    >> New Migrations:                                     0

コマンドを実行するとデータベースに migration_versions テーブルができます。

mysql> show tables;
+--------------------+
| Tables_in_hoge     |
+--------------------+
| migration_versions |
+--------------------+

マイグレーションファイルを作成する

app/console doctrine:migrations:generate コマンドを実行してマイグレーションファイルを作成します。

$ php app/console doctrine:migrations:generate
Generated new migration class to "/app/DoctrineMigrations/Version20131102234017.php"

app/DoctrineMigrations/Version20131102234017.php ができました。このファイルの up メソッドに、適用する SQL を記述します。

public function up(Schema $schema)
{
    $sql = <<<SQL
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SQL;
    $this->addSql($sql);

    $sql = <<<SQL
CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(255),
  `password` varchar(50),
  `name` varchar(50) DEFAULT NULL
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
SQL;
    $this->addSql($sql);

    $sql = <<<SQL
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SQL;
    $this->addSql($sql);
}

down メソッドに変更を巻き戻す SQL を記述します。

public function down(Schema $schema)
{
    $sql = <<<SQL
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SQL;
    $this->addSql($sql);

    $sql = <<<SQL
DROP TABLE IF EXISTS `user`;
SQL;
    $this->addSql($sql);

    $sql = <<<SQL
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SQL;
    $this->addSql($sql);
}

SET FOREIGN_KEY_CHECKS=0; のクエリを実行すると、FOREIGN KEY 制約で怒られなくなるのでテーブル登録をスムーズに行うことができます。Symfony2 では FOREIGN KEY 制約を入れると便利なことが多いので、CREATE TABLE 系のクエリを実行するときは毎回指定しています。

マイグレーション実行

マイグレーションファイルができたら、再度 doctrine:migrations:status コマンドを実行してみます。

$ php app/console doctrine:migrations:status
 == Configuration
...
    >> Current Version:                                    0
    >> Latest Version:                                     2013-11-02 23:40:17 (20131102234017)
    >> Executed Migrations:                                0
    >> Executed Unavailable Migrations:                    0
    >> Available Migrations:                               1
    >> New Migrations:                                     1

作成したマイグレーションファイルが変更として現れました。New Migrations :1 と表示され、Current Version と Latest Version もずれています。doctrine:migrations:migrate コマンドで変更を反映してみましょう。

$ php app/console doctrine:migrations:migrate
Application Migrations
...
  ++ finished in 0.1
  ++ 1 migrations executed
  ++ 3 sql queries

再度 status を確認します。変更が反映されました。

$ php app/console doctrine:migrations:status
 == Configuration
...
    >> Current Version:                                    2013-11-02 23:40:17 (20131102234017)
    >> Latest Version:                                     2013-11-02 23:40:17 (20131102234017)
    >> Executed Migrations:                                1
    >> Executed Unavailable Migrations:                    0
    >> Available Migrations:                               1
    >> New Migrations:                                     0

doctrine:migrations:migrate --no-interaction のように --no-interaction オプションを指定すると、確認メッセージを省略できます。ワンクリックデプロイの際に役立つので覚えておきましょう。

変更をもとに戻す

変更を元に戻す場合は以下のコマンドを実行します。

$ php app/console doctrine:migrations:execute --down 20131102234017
  -- reverting 20131102234017
...
  -- reverted (0.18s)

マイグレーションが壊れてしまった場合は

マイグレーションを実行せずにデータベースに直接クエリを実行したりすると、以下のように Executed Unavailable Migrations:1 の状態になることがあります。

$ app/console doctrine:migrations:status
 == Configuration
    >> Current Version:                                    2013-11-09 00:37:00 (20131109003700)
    >> Latest Version:                                     2013-11-09 00:37:00 (20131109003700)
    >> Executed Migrations:                                2
    >> Executed Unavailable Migrations:                    1
    >> Available Migrations:                               1
    >> New Migrations:                                     0
WARNING! You have 1 previously executed migrations in the database that are not registered migrations.
    >> 2013-11-02 23:40:17 (20131102234017)

マイグレーションデータベースとマイグレーションファイルがずれている状態です。多くの場合、マイグレーションの適用履歴を削除することで解決します。

$ php app/console doctrine:migrations:version --delete 20131102234017

その他の使い方

各コマンドのヘルプに大体書いてあります。

$ php app/console doctrine:migrations:migrate --help

-技術ブログ
-