LoginSignup
13
13

More than 5 years have passed since last update.

FuelPHPで,リフレクションを使ってOrm\Modelのキャッシュをクリアする

Last updated at Posted at 2015-06-18

FuelPHPのORMにはキャッシュ機能があるが,場合によっては邪魔になってしまう.

キャッシュ機能については
http://tech.respect-pal.jp/fuelphp-orm-cache/
に詳しい解説がある.

今回,DBへのアクセスが発生するユニットテストで
「テストケースごとにテーブルをTRUNCATEしているのに,ORMのキャッシュ機能のせいで前のテストケースで行われた変更が次のテストケースに影響を与えてしまう」
という問題に遭遇した.
(テストは,https://phpunit.de/manual/current/ja/database.html を参考にし,テストケースごとに自動でテーブルのTRUNCATEとフィクスチャのロードが行われるようにしている)

例えば,テストケースAで

$obj = Model_Foo::forge(array('id' => 1));
$obj->save();

したあと,
テストケースBで

if (Model_Foo::find(1))
{
    echo 'exists';
}

などとすると,テストケースごとにTRUNCATEしているのにテストケースBでModel_Fooのエンティティが取り出されてしまう.

この問題に対し,ORMのキャッシュをクリアすることで解決を図った.

リフレクションによる解決

Orm\Model$_cached_objectsという静的プロパティにオブジェクトをキャッシュしているが,
Orm\Modelにはこの変数をクリアするメソッドが提供されていない.

http://tech.respect-pal.jp/fuelphp-orm-cache/ ではOrm\Modelを継承した独自クラスを作り,$_cached_objectsをクリアするメソッドを追加して解決している.

しかし,既に多くのクラスがOrm\Modelを継承するようになっているのを,独自クラスを継承するよう書きなおすのはしたくなかったので,
(テストでのみ利用される独自クラスを定義してテスト用のbootstrapで読み込むようにしてもよかったのだが,)
今回はリフレクションを使ってキャッシュをクリアするようにした.
これによりメインのコードには変更を加えず,テスト用コードのみの変更で済む.

具体的には,

// Orm\Model::$_cached_objectsをクリアする
$model_reflection = new \ReflectionClass('Orm\\Model');
$prop = $model_reflection->getProperty('_cached_objects');
$prop->setAccessible(true);
$prop->setValue(null, array());

のようにする.
これを各テストケース実行時に呼べば良い.

私はDB接続があるテストが共通して継承する親クラスのsetup()に書いている.

    protected function setup()
    {
        parent::setup();

        // Orm\Model::$_cached_objectsをクリアする
        $model_reflection = new \ReflectionClass('Orm\\Model');
        $prop = $model_reflection->getProperty('_cached_objects');
        $prop->setAccessible(true);
        $prop->setValue(null, array());
    }
13
13
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
13