[share] Mixed with CMemCache and CActiveDataProvider.

This is just my opinion of that. :)

because I use the cache system in the models, so when using with CActiveDataProvider, the pages will not take effect.

I made some modifies to achieve it.

Model:




class Product extends CActiveRecord

{

    public $cacheKey = 'product'; //this is used for seperate the different cache values, we will see it below.

    //.......other codes

    

    //To newbie: Why i override this method? Because CActiveDataProvider use it to fetch the data from database.

    public function findAll($condition='',$params=array())

    {

        $cache = Yii::app()->cache;

        if ($cache->get($this->cacheKey) === false)

        {

            $rs =  parent::findAll($condition, $params);

            $cache->set($this->cacheKey, $rs, 30);

        }

        else

        {

            $rs = $cache->get($this->cacheKey);

        }

        return $rs;

    }

}



Create a class MyActiveDataProvider which implement the CActiveDataProvider. That serves for overriding the fetchData() method in CActiveDataProvider, set the value of cacheKey in model (about the cacheKey, please see above.)




class MyActiveDataProvider extends CActiveDataProvider

{

    public $modelCacheKey; //this parameter is used to set the cacheKey in the model.

    

    //override the method of parent.

    protected function fetchData()

    {

        $criteria=clone $this->getCriteria();

        $baseCriteria=$this->model->getDbCriteria(false);


        if(($pagination=$this->getPagination())!==false)

        {

            if($baseCriteria!==null)

                $this->model->setDbCriteria(clone $baseCriteria);

            $pagination->setItemCount($this->getTotalItemCount());

            $pagination->applyLimit($criteria);

        }


        if(($sort=$this->getSort())!==false)

        {

            if($baseCriteria!==null)

            {

                $c=clone $baseCriteria;

                $c->mergeWith($criteria);

                $this->model->setDbCriteria($c);

             }

             else

                 $this->model->setDbCriteria($criteria);

             $sort->applyOrder($criteria);

         }

                

        //set the value to the cacheKey.

        if (!empty($this->modelCacheKey))

        {

            $this->model->cacheKey = $this->modelCacheKey;

        }


        $this->model->setDbCriteria($baseCriteria);

        return $this->model->findAll($criteria);

    }

}



Controller:




public function actionIndex()

{

    //in this action, i instance the MyActionDataProvider twist, get the data from Product model.

    $modelCacheKey = empty($_GET['hot']) ? 'site_index_hot_0' : 'site_index_hot_'.$_GET['hot'];


    $ads = new MyActiveDataProvider(

        'Product', 

        array(

            'criteria'=>array(

                'condition'=>'display=1 AND ad=1',

            ),

        )

    );


    $models = new MyActiveDataProvider(

        'Product',

        array(

            'criteria'=>array(

                'condition'=>'display=1 ad<>1',

            ),

            'pagination'=>array(

                'pageSize'=>2,

                'pageVar'=>'hot',

            ),

            'modelCacheKey'=>$modelCacheKey, //Please be aware of this code, i set the cacheKey via MyActiveDataProvider!

        )

    );


    $this->render(

        'index',

        array(

            "models"=>$models,

            "ads"=>$ads,

        )

    );

}



View:




<?php $this->widget('zii.widgets.CListView', array(

    'ajaxUpdate'=>false,

    'dataProvider'=>$models,

    'itemView'=>'_view_models',

    'itemsTagName'=>'ul',

    'itemsCssClass'=>'lists',

    'template'=>"{items}\n{pager}",

    'viewData'=>array('modelsCount'=>count($models->getData())),

    'pager'=>array(

                'class'=>'CLinkPager',

                'header'=>'',

                'cssFile'=>$this->themeCss('pager.css'),

            )

)); ?>



Maybe FAQ:

  1. Why i defined a parameter $cacheKey in the model?

Because in the cache, we have to get the different data with different key, the same to the array($key=>$value), in addition, in the controller, I instance the MyActiveDataProvider twist to get the different data from Product model, if both of them are been cached, when fething data from the cache, they will be the same. Also the pages of CListView.

  1. Why i create a class which implement the CActiveDataProvider?

As mentioned in the code above, i have to set the value to $cacheKey.

  1. What can the code be use for?

Sorry, i have no idea, because I just want to test CMemCache and CActiveDataProvider. :P

Welcome give me the feedback about this topic, and discuss. thank you. :)

Hello, everybody, hope for your feedback :)

Thank you very much!

I realized the need for a data provider caching solution. The next day you posted this solution. :)

I modified the key to handle sorting as well:




$modelCacheKey =

  (empty($_GET['page']) ? 'controller_action' : 'controller_action_page_'.$_GET['page'])

  . (empty($_GET['sort']) ? '' : '_sort_'.$_GET['sort']);



It seems to work but will need more testing. Probably best suitable for multiSort=false.

/Tommy

Thank you very much Davidhhuan. All works fine. http://ovlix.com/ca

我特意到这里来看你 :blink: 很想帮你,但是现在不够火候