CakePHP 3.x:缓存分页搜索

时间:2015-10-05 12:38:49

标签: cakephp caching pagination cakephp-3.0

我需要在CakePHP 3分页搜索中缓存分页结果。

当我使用CakePHP 2.x时,我能够在appModel中覆盖paginate函数。使用新的CakePHP ORM可以获得相同的结果吗?因为$query->cache()在分页查询对象中不起作用。

我已经阅读过有关此主题的一些讨论,但如果可能,我需要一个例子。

2 个答案:

答案 0 :(得分:5)

分页查询

问题中没有显示代码,但我们假设您从一个简单的烘焙控制器索引操作开始:

public function index()
{   
    $this->set('posts', $this->paginate($this->Posts));
    $this->set('_serialize', ['posts']);
}

首先,识别控制器方法paginate accepts a table or query object - 并且如果表对象传递了paginator组件simply calls find以使用查询对象。所以,上面的代码在功能上等同于:

public function index()
{   
    $query = $this->Posts->find();

    $this->set('posts', $this->paginate($query));
    $this->set('_serialize', ['posts']);
}

使用查询缓存方法

只需对上述代码进行一些小修改即可使用查询的缓存方法:

public function index()
{
    $query = $this->Posts->find();

    $cacheKey = $this->name . '_' . md5(json_encode($this->request->query));
    $query->cache($cacheKey);

    $this->set('posts', $this->paginate($query));
    $this->set('_serialize', ['posts']);
}

查询参数和控制器名称用于生成唯一的缓存键,以便一次调用paginate的缓存结果不会与另一个请求的调用混淆。

照顾计数

当以这种方式使用时仍会发出计数,如果这是一个问题,仍然可以通过定义a counter callback来阻止它:

public function index()
{
    $query = $this->Posts->find();

    $cacheKey = $this->name . '_' . md5(json_encode($this->request->query));
    $searchTerms = []; // define this
    $countCacheKey = $this->name . '_' . md5(json_encode($searchTerms)) . '_count';

    $query
        ->cache($cacheKey)
        ->counter(function($query) use ($countCacheKey) {
            return Cache::remember($countCacheKey, function()  use ($query) {
                return $query->count();
            }); 
        }); 


    $this->set('posts', $this->paginate($query));
    $this->set('_serialize', ['posts']);
}

即。只需将调用包装到Cache::remember中的count方法。

请注意,答案中用于计数的缓存键对于所有请求都是相同的,因为在此示例中要分页的行数对于所有请求都相同。如果您要对搜索进行分页 - 例如,搜索词应该用于计数缓存键。

答案 1 :(得分:1)

重要的是,除了记录之外,你必须缓存分页的参数,这些还不够。

因此,您无法使用cache的{​​{1}}选项。

<强> WRONG:

find()

从右:

$posts = $this->Posts->find('all')
    ->cache('posts_index')
    ->toArray();

$this->set(compact('posts'));

因此,例如,对于帖子的第一页,您必须使用缓存中的两个值://Sets the cache names $cache_posts = 'posts_index_page_' . ($this->request->query('page') ? $this->request->query('page') : 1); $cache_paging = $cache_posts . '_paging'; //Tries to get data from the cache list($posts, $paging) = array_values(Cache::readMany([$cache_posts, $cache_paging])); //If the data are not available from the cache if(empty($posts) || empty($paging)) { //Gets posts $posts = $this->paginate($this->Posts->find('active'))->toArray(); //Writes on cache Cache::writeMany([$cache_posts => $posts, $cache_paging => $this->request->param('paging')]); } //Else, sets the paging parameter else $this->request->params['paging'] = $paging; $this->set(compact('posts')); posts_index_page_1。第二个包含数据分页。

另见