我需要在CakePHP 3分页搜索中缓存分页结果。
当我使用CakePHP 2.x时,我能够在appModel中覆盖paginate函数。使用新的CakePHP ORM可以获得相同的结果吗?因为$query->cache()
在分页查询对象中不起作用。
我已经阅读过有关此主题的一些讨论,但如果可能,我需要一个例子。
答案 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
。第二个包含数据分页。
另见