3

CActiveDataProvider インスタンスの DB 結果をキャッシュしたいと考えています。

コントローラーのアクションでデータ プロバイダーを準備してから、CGridView でデータ プロバイダーを使用し、後でいくつかのビューで使用します。

私はこのコードを持っていました:

$cars=new CActiveDataProvider(
    'Car'
    ,
    array(
        'criteria'=>array(
            'condition'=>'brand_id=:brand_id',
            'params' => array(':brand_id'=>$model->id),
            'order' => 'price',
        ),
        'pagination'=>false,
    )
);

そして、yii wiki のチュートリアルに従って、次のように変更しました。

$cars=new CActiveDataProvider(
        Car::model()->cache(3600)
        ,
        array(
            'criteria'=>array(
                'condition'=>'brand_id=:brand_id',
                'params' => array(':brand_id'=>$model->id),
                'order' => 'price',
            ),
            'pagination'=>false,
        )
    );

しかし、役に立たない: クエリはキャッシュされていません。

4

1 に答える 1

2

CActiveDataProvider の利点の 1 つは、クエリがすぐに実行されないことです。クエリは、CActiveDataProvider を後で使用する場合にのみ実行されます。たとえば、CGridView で、CActiveDataProvider::fetchData最終的にクエリのトリガーを呼び出します。

これは、フラグメント キャッシングを使用できるため便利です。また、フラグメントがキャッシュされているため、コントローラにデータをロードして不要であることが判明することは避けたいと考えています。

これはまさにここで起こっていることです: ActiveRecord->cache()メソッドは DB 接続に後続のクエリをキャッシュするように指示しますが、クエリがすぐに実行されない場合、このクエリの前に他のクエリが実行される可能性があり、このキャッシュは機能しません。

クエリが実行される直前にモデル キャッシュを設定するパーソナライズされた ActiveDataProvider を作成する問題を解決しました。

class CachedActiveDataProvider extends CActiveDataProvider
{

    public $cache_duration = null;
    public $cache_dependency = null;

    /**
     * The cache mechanism works by telling the DB Component to cache the next query.
     * When  fetchData() is called, the DB will cache the next query. 
     * There is a possibility that fetchData call calculateTotalItemCount()
     * and in that function, if this bit is active, we will tell the DB to cache
     * 2 queries, the count, and the actual fetch that will come next.
     * (if we don't do this, the DB will cache the count query, and will forget about
     * the instruction to cache the fetch query)
     * 
     * @var boolean
     */
    private $fetching_data = false;

    protected function fetchData()
    {
        if (!is_null($this->cache_duration ))
        {
            $this->model->cache($this->cache_duration, $this->cache_dependency);
        }

        $this->fetching_data = true;
        $ret = parent::fetchData();
        $this->fetching_data = false;

        return $ret;
    }

    protected function calculateTotalItemCount()
    {
        if (!is_null($this->cache_duration ))
        {
            $this->model->cache(
                $this->cache_duration, 
                $this->cache_dependency, 
                $this->fetching_data ? 2 : 1 //if fetching data, cache 2 queries: this count and the sequent fetching
            );
        }

        return parent::calculateTotalItemCount();
    }
}

を使用して呼び出すことができるようになりました

$cars=new CachedActiveDataProvider(
    'Car'
    ,
    array(
        'criteria'=>array(
            'condition'=>'brand_id=:brand_id',
            'params' => array(':brand_id'=>$model->id),
            'order' => 'price',
        ),
        'pagination'=>false,
        'cache_duration' => 3600,
    )
);
于 2013-08-29T16:58:05.210 に答える