DoctrineMigrationsBundleで複数データーベース対応できるようにしてみたpart2

DoctrineMigrationsBundleで複数データーベース対応できるようにしてみたpart2

June 19, 2015,
tags: php symfony doctrine2 migration


このエントリーをはてなブックマークに追加

ご無沙汰しています。ポリドッグです。

前回DoctrineMigrationsBundleで複数データーベース対応できるようにしてみたを書きましたが、今回はその追記というか、 前回の記事のアプローチが間違ってたので、最近の僕の対応方法をご紹介しようと思います。

前回のアプローチにはどのような問題があっのか?

そもそもとしてMySQL用、PostgreSQL用のAbstractMigrationクラスを作成するってことを考えている時点で負け組なんですよね。 まあ前回の記事書いた当時は、mysqlとPostgreSQLを併用していたので、あの方法でも対応できたんですが、、、mysqlで複数コネクションを持ちたいって事も多々あるんですよね。

Symfony的は複数コネクションをどう分けているのか。

Symfony的には複数のデータベースのコネクションを持つ時はDBALのconnectionsで管理してますよね。 config.ymlとかにこんな感じに書いていると思います。

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   "%database_driver%"
                host:     "%database_host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8
            log:
                driver:   "%log_database_driver%"
                host:     "%log_database_host%"
                port:     "%log_database_port%"
                dbname:   "%log_database_name%"
                user:     "%log_database_user%"
                password: "%log_database_password%"
                charset:  UTF8

つまり、マイグレーションでもdefaultlogといったコネクション名を指定したらいい感じになってくれるのが望ましいんですよ。

解決策

正しい解決策なのかは、わかりませんが本家のドキュメントを見ていると ContainerAwareInterfaceimplementsすれば、サービコンテナを利用することができます。
ということは、コンテナから対象のデータベースのコネクションオブジェクトを取得してAbstractMigration側でもっているコネクションと一致すればマイグレーションを実行するといった感じの実装にしてあげればいいんですよね。

ということで以下のようにAbstractMigrationを継承したCustomMigrationクラスを作成します。

<?php
namespace AppBundle\Doctrine\DBAL\Migrations;


use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class CustomMigration extends AbstractMigration implements ContainerAwareInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    protected $targetConnection = 'default';

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    public function preUp(Schema $schema)
    {
        $this->skipIf($this->container->get("doctrine.dbal.{$this->targetConnection}_connection") !== $this->connection, 'other connection database name');
    }

    public function preDown(Schema $schema)
    {
        $this->skipIf($this->container->get("doctrine.dbal.{$this->targetConnection}_connection") !== $this->connection, 'other connection database name');
    }

}

skipIfメソッドとpreUp,preDownメソッドを活用してCustomMigrationクラスを作成しました。 AbstractMigration側で持っているコネクションとCustomMigration::$targetConnectionで期待しているコネクションが一致してなければ、マイグレーションをスキップするようにしています。 これによって、うまくマイグレーションが実行できるようになります。

targetConnectionのクラス変数にコネクション名を入れれば、あとはいい感じにマイグレーションできるわけです。

最後に

どのマイグレーションファイルがどのコネクション用なのかも、ファイルを見てわかりやすいのでこの方法はかなりおすすめですよ! 他にもやり方があるような気もするので、良い方法をご存知の方がいらっしゃいましたら教えてくださいw

おしまい。

comments powered by Disqus