こんにちは、habrasociety!
問題
データベースを使用したり、アプリケーションのさまざまな部分からアクセスできるオブジェクトを使用したりする場合、同等であると思われるオブジェクトがまったく存在しないという危険があります。
たとえば、いくつかのActiveRecordモデル、Expence、およびこのコードがあるとします。
$modelOne = Expence::model()->findByPk(10); $modelTwo = Expence::model()->findByPk(10); var_dump($modelOne === $modelTwo);
したがって、1つのモデルを変更しても、2番目のモデルには影響しません(異なるオブジェクトを参照するため、論理的です)。
$modelOne->someField = "Data"; $modelOne->save();
解決策
この問題を解決するために、Martin Fowler
Identity Mapという設計パターンを使用します。
彼のアイデアは、同じ識別子を持つアプリケーション内のオブジェクトの存在を追跡することです。 したがって、プログラムの2つの異なる場所でidが5のモデルを要求すると、同じオブジェクトへのリンクが取得されます。
実装
残念ながら、Yiiはデータベースからオブジェクトを要求したかどうかを監視しないため、独自のクラスを作成する必要があります。
<?php class ObjectWatcher { private static $_instance; private $objects = array(); static function getInstance(){ if(!isset(self::$_instance)){ self::$_instance = new ObjectWatcher; } return self::$_instance; } static function getRecord($className, $id) { $inst = self::getInstance(); $key = "$className.$id"; if(isset($inst->objects[$key])){ return $inst->objects[$key]; } return null; } static function addRecord($obj, $id) { $inst = self::getInstance(); $inst->objects[$inst->getKey($obj, $id)] = $obj; } function getKey($obj, $id){ return get_class($obj).'.'.$id; } }
addRecordメソッドとgetRecordメソッドを使用して、モデルの固有のレジストリ( "class_name.id" =>オブジェクトの形式の連想配列)からモデルを追加および取得します。
ここで、まだ受け取っていない場合はYiiにオブジェクトを作成させるか、$ objects配列から既存のオブジェクトを返す必要があります。 CActiveRecordの後に余分なレイヤーを作成せずに、Yiiツールを使用してこれを実行しようとします。 もちろん、Expence :: model()-> findByPk(10)を実行した後、データベースを照会せずに以前に取得したオブジェクトを返しますが、Yiiにはこの照会をインターセプトするメカニズムはありません。 はい、CActiveRecord :: beforeFind()がありますが、特にfindByPk()の後に、リクエストに関するデータを取得することはできません。 モデルインスタンスは、CActiveRecord :: instantiate()メソッドで作成されます。 モデルで再定義します。
<?php class Expence extends CActiveRecord {
これですべてです
$modelOne = Expence::model()->findByPk(10); $modelTwo = Expence::model()->findByPk(10); var_dump($modelOne === $modelTwo);
参照: