すべての読み取りは 1 つの DB 接続に移動する必要があります すべての書き込みは別の接続に移動する必要があります
コア ライブラリのコードを最小限に変更して、Yii でこれを達成するにはどうすればよいですか?
また、場合によっては (コメントに記載されているように)、接続の各モデル タイプを制御する機能が必要になるため、読み取りもマスターに移動できます。
すべての読み取りは 1 つの DB 接続に移動する必要があります すべての書き込みは別の接続に移動する必要があります
コア ライブラリのコードを最小限に変更して、Yii でこれを達成するにはどうすればよいですか?
また、場合によっては (コメントに記載されているように)、接続の各モデル タイプを制御する機能が必要になるため、読み取りもマスターに移動できます。
マスター管理パネルを使用して顧客向けの「インスタンス」をいくつか作成および管理できるアプリを作成したので、マスター アプリ内で実行されているクエリをインスタンス固有のデータベースのいずれかに「転送」する必要がありました。私が最初に行ったことを簡略化したバージョン (目標ほど厳しいものではありません) を示し、後でより強力なアプローチを示します。
事前に指定されたデータベースにクエリを送信するのは簡単ですCActiveRecord::getDbConnection
。メソッドをオーバーライドするだけです。私がしたことはこれに切り詰めることができます:
abstract class InstanceActiveRecord extends CActiveRecord {
public static $dbConnection = null;
public function getDbConnection() {
if (self::$dbConnection === null) {
throw new CException('Database connection must be defined to work with instance records.');
}
return self::$dbConnection;
}
}
したがって、すべての操作を特定のデータベースに向けたい場合は、 ActiveRecord モデルをInstanceActiveRecord
の代わりにから派生させるCActiveRecord
だけでInstanceActiveRecord::dbConnection = $connection
よいのです。
このためには、さらに深く掘り下げる必要がありますCActiveRecord
。getDbConnection
が主に によって使用されていることがわかりgetCommandBuilder
ます。これは、すべての削除/更新/挿入ファミリによって呼び出されるメソッドです。したがって、これらの関数から何らかのコンテキストを に渡す必要がありますgetDbConnection
。ここで、使用する接続の選択が行われます。
このために、これらのファミリのすべてのメソッドをオーバーライドする必要があるため、合理的なアプローチは次のようになります。
ステップ 1.オプションのパラメーターを追加しgetDbConnection
てオーバーライドし、パラメーター値に基づいて必要な接続を返します。最も簡単なのは次のようなものです。
public function getDbConnection($writeContext = null) {
if ($writeContext === null) {
return parent::getDbConnection(); // to make sure nothing will ever break
}
// You need to get the values for $writeDb and $readDb in here somehow,
// but this can be as trivially easy as you like (e.g. public static prop)
return $writeContext ? $writeDb : $readDb;
}
ステップ 2.オプションのパラメータをgetCommandBuilder
同じセマンティクスで追加し、それをオーバーライドして値を転送します。
public function getCommandBuilder($writeContext = null) {
return $this->getDbConnection($writeContext)->getSchema()->getCommandBuilder();
}
ステップ 3.getCommandBuilder
(それらの束があるでしょう) とgetDbConnection
(私が見たときに内部のものよりも 2 つだけ多かった)のすべての呼び出しサイトを見つけgetCommandBuilder
、それらをオーバーライドして、読み取り/書き込みコンテキストを適切に指定します。例:
public function deleteAll($condition='',$params=array()) {
Yii::trace(get_class($this).'.deleteAll()','system.db.ar.CActiveRecord');
// Just need to add the (true) value here to specify write context:
$builder=$this->getCommandBuilder(true);
$criteria=$builder->createCriteria($condition,$params);
$command=$builder->createDeleteCommand($this->getTableSchema(),$criteria);
return $command->execute();
}
これで準備完了です。true
また、ここに示した/オプションよりも複雑なコンテキスト選択メカニズムを作成することを妨げるものは何もありませんfalse
。概念は同じです。
これらはすべて、記載された目標を完全に達成しますが、このアプローチの保守性に関しては疑問が残ります。
このルートに進むと、 からコピー/貼り付けされた多くのコードが必要になることは事実ですCActiveRecord
。これは、後でアプリを新しいバージョンのフレームワークに移行する可能性がある場合には理想的ではありません。そのためには、サブクラスを最新バージョンの と同期させる必要がありますCActiveRecord
。
これを軽減し、将来の生活を楽にするために、次のアプローチを検討できます。
CActiveRecord
、 の正確なコピー (もちろんプロパティを除く) を作成CActiveRecord
し、そこで変更を実行します。つまり、オーバーライドするつもりのないメソッドもコピーしてください。getDbConnection
他の 12 か 2 か所のオーバーライドとほんのわずかな編集が含まれることに注意してください。Yii の新しいバージョンにアップグレードするときが来たら、クラスを とCActiveRecord
再び同期させる必要があります。お気に入りの差分ツールを起動して、クラスをターゲット バージョンの と比較しますCActiveRecord
。diff ツールは、とマイナーな編集、およびYii のコアにgetDbConnection
加えられた変更のみを表示します。CActiveRecord
これらの他の変更をクラスにコピーします。問題は 5 分で解決します。