CakePHPのデータベースを開発環境と本番環境で切り分ける方法

CakePHPには利用するデータベース定義を複数定義しておける機能がありますが、その使い分けに関するアイデアです。

よくある解決策

よく開発環境と本番環境で自動的にデータベース接続を切り替えられるように、以下のようにDATABASE_CONFIGクラスのコンストラクタを改良したり、AppModelクラスのコンストラクタに現在の環境を判別できるような設定を書いたりするアイデア多く見かけられます。

DATABASE_CONFIGクラスの改良

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		if (env('SERVER_ADDR') !== '127.0.0.1') {
			$this->default = $this->production;

		} else {
			$this->default = $this->development;
		}
	}
}

AppModelの改良

function __construct()
{
	if (env('SERVER_ADDR') == '127.0.0.1') {
		$this->useDbConfig = 'development';
	}  else {
		$this->useDbConfig = 'production';
	}
}

よくある解決策の問題点

よくある解決策では、httpから利用する場合には非常に便利で良いのですが、コンソールから利用する場合、この設定では不都合が発生します。

たとえばschemaコマンドを利用する場合です。
コンソールではREMOTE_ADDRやSERVER_ADDRなどの環境変数が利用できません。
そのため、コンソールで利用する場合はリモートで利用しているのかローカルで利用しているのかを環境変数から判別することができません。

であれば、schemaコマンドを実行する際に -connectionオプションで利用する接続を選択してやれば良いと考えてしまうのですが、CakePHPのコンソールから起動するschemaコマンドは、-connectionオプションで指定されたデータベース接続(指定されなければdefault)とModelのデータベース接続(Model::$useDbConfig)が一致しない場合、そのModelのスキーマを読み込んでくれません。

実行しているファイルのパスを見て判別するような荒技もありますが、実行ファイルのパスが被らない保証も無いので、こちらも確実とはいえません。

シンプルな解決策

ではどうすれば良いか、というと、Configureクラスを利用する方法が一番わかりやすくてベターです。
config/core.php もしくは config/bootstrap.php に下記のように設定します。

Configure::write('database', 'production');

そして、config/database.php のDATABASE_CONFIGクラスを下記のように記述します。

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		$connection = Configure::read('database');
		
		if (!empty($this->{$connection})) {
			$this->default = $this->{$connection};
		}
	}
}

この方法であれば、データベースを切り替えたいときはデバッグモードの切り替えのように設定値を変更するだけで済みますし、ローカルに依存するコードを記述する必要もなくなります。

さらに今後新しいデータベース接続を追加した場合にも、設定値を変更するだけで対応可能なので、今後の拡張性の面でも安心できます。