Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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());
    }
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away