Yii2 : how to cache active data provider?
Asked Answered
B

1

14

In my PostSearch model I have this code :

public function search($params)
{
    $query = Post::find()->where(['status' => 1]);

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
        'sort'=> ['defaultOrder' => ['id' => SORT_DESC]],
        'pagination' => [
            'pageSize' => 10,
        ]
    ]);

    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }

    $query->andFilterWhere([
        'id' => $this->id,
        'status' => $this->status,
    ]);

    $query->andFilterWhere(['like', 'title', $this->title])
        ->andFilterWhere(['like', 'text', $this->text]);

    return $dataProvider;

my try, instead of above line return $dataProvider, would be this block of code:

$dependency = [
    'class' => 'yii\caching\DbDependency',
    'sql' => 'SELECT MAX(updated_at) FROM post',
];

$result = self::getDb()->cache(function ($db) {
    return $dataProvider;
}, 3600, $dependency);

return $result

I would like to cache the result returned by ADP, based on the updated_at field. I mean I want to serve data from cache until some change is made. My code does not work, I mean caching is not applied at all. What I am doing wrong, and is it possible to do this on ADP ? Thanks

Boatman answered 17/6, 2015 at 11:6 Comment(0)
P
20

It has little use caching the data provider after instantiating, since it's not actually doing any selecting on the database until it has been prepared. So you would actually be caching an empty object instance like it is now.

If you have a very large set of records, call the dataProviders' prepare() in advance in the cache:

 self::getDb()->cache(function ($db) use ($dataProvider) {
     $dataProvider->prepare();
 }, 3600, $dependency);
 return $dataProvider;

This will actually cache whatever queries the dataProvider runs ,so the next time they will be fetched from the query cache. This should result in what you are looking for.

If you have a finite amount of records, caching them all at once could also work:

$key = 'MyCachedData'; // + Data uniquely referring to your search parameters
$cache = \Yii::$app->cache;
$dataProvider = $cache->get($key);
if (!$dataProvider) {
   $dependency = \Yii::createObject([
      'class' => 'yii\caching\DbDependency',
      'sql' => 'SELECT MAX(updated_at) FROM post',
   ]);

   $dataProvider = new \yii\data\ArrayDataProvider;
   $dataProvider->allModels = $query->all();
   $cache->set($key, $dataProvider, 3600, $dependency) 
} 
return $dataProvider;

Obviously this is less than ideal for larger datasets, but it depends on what you are looking for.

Paw answered 18/6, 2015 at 5:39 Comment(4)
Thank you, solution with prepare() works, but I do not understand your second code very well. What is ->allModels and $postActiveQuery ? Thanks again.Boatman
Actually just $query was enough. It's the same principle as the first piece, but instead we fetch all records and store them into an ArrayDataProvider. The difference is that now the actual models/attributes are cached in the application cache instead of the results of the query. But if the first one works I would stick to that :)Paw
@Paw I tested your first solution, that caches select query, but does not cache count query of dataProvider. How can I fix this to cache both select and count queires? I'm using SqlDataProvider.Immersion
very well explained. Thank you @PawMaffick

© 2022 - 2024 — McMap. All rights reserved.