【问题标题】:CakePHP 3.x: Cache paginated searchCakePHP 3.x:缓存分页搜索
【发布时间】:2016-01-02 02:58:58
【问题描述】:

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

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

我已经阅读了一些关于这个主题的讨论,但如果可能的话,我需要一个例子。

【问题讨论】:

  • 你需要展示一些代码。 I have already read some discussion regarding this topic - 什么讨论? does not work - 以什么方式?分页is just a query,对调用分页结果的查询可以做的任何事情;您需要展示和询问特定的内容而不是未展示的代码不起作用,并得到未链接对话的支持。

标签: cakephp caching pagination cakephp-3.0


【解决方案1】:

对查询进行分页

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

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

首先,认识到控制器方法 paginate accepts a table or query object - 如果传递了一个表对象,则分页器组件 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']);
}

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

照顾计数

以这种方式使用时仍然会发出计数,如果这是一个问题,仍然可以通过定义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']);
}

即只需将 count 方法的调用封装在 Cache::remember 中即可。

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

【讨论】:

    【解决方案2】:

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

    所以你不能使用find()cache选项。

    错误:

    $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_1posts_index_page_1_paging。第二个包含数据分页。

    另见

    【讨论】:

    • @AD7six,你测试你的代码了吗?看起来很有趣。我会尽快尝试。
    • @ADsix,我看不懂你的代码。记住:你必须缓存两个记录,两个分页参数......
    • @AD7six,是的,它有效。谢谢。在您的示例中,为什么将 cacheKey 设置为视图(第 26 行)?
    • @AD7six,不,这不起作用,没有 che 分页参数我有一个计数帖子的查询。在您的屏幕截图中,您有 1 个页面,您是否尝试过更多页面?
    • 另外,请清理您以前寄给我的 cmets - 他们达到了他们的目的,我已经阅读了他们。他们不会为其他任何人增加任何价值。
    猜你喜欢
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 2012-04-27
    • 2015-05-10
    • 2012-09-22
    • 2015-06-19
    • 1970-01-01
    • 2017-12-22
    相关资源
    最近更新 更多