CakePHP 分页:如何按多列排序以实现“粘性”功能?

Posted

技术标签:

【中文标题】CakePHP 分页:如何按多列排序以实现“粘性”功能?【英文标题】:CakePHP Pagination: how can I sort by multiple columns to achieve "sticky" functionality? 【发布时间】:2012-11-29 14:41:25 【问题描述】:

我看到这张paginate can't sort two columns at the same time 票仍然开放,这让我相信如果没有解决方法,我正在尝试做的事情是不可能的。所以我想我正在寻找一种解决方法。

我正在尝试做许多留言板所做的事情:拥有“sticky”功能。我想这样做,无论用户单击哪个表头链接进行排序,我的模型的“sticky”字段始终是排序的第一件事,然后是用户单击的任何列。我知道您可以将$this->paginate['Model']['order'] 设置为您想要的任何值,因此您可以破解它以将“sticky”字段放在第一位,将用户选择的列放在第二位。这种方法的问题是分页在您执行后无法正常运行。表头链接不能正常工作,切换页面也不能正常工作。还有其他解决方法吗?

【问题讨论】:

【参考方案1】:

Cakephp IRC 频道上的用户 ten1 帮助我找到了解决方案。我告诉他,如果他在这里发布答案,那么我会将其标记为正确的,但他说我应该自己做,因为他还没有 Stack Overflow 帐户。

诀窍是使用模型的“beforeFind”回调方法将“粘性”字段注入查询的“订单”设置,如下所示:

public function beforeFind($queryData) 
    $sticky = array('Model.sticky' => 'DESC');

    if (is_array($queryData['order'][0])) 
        $queryData['order'][0] = $sticky + $queryData['order'][0];
    
    else 
        $queryData['order'][0] = $sticky;
    

    return $queryData;

【讨论】:

简洁明了!谢谢:-) 一个简单的点赞并没有显示出我对这个答案的欣赏程度,所以这里有一条真正让你知道的评论!【参考方案2】:

您可以做的是在操作中对其进行编码。当 URL 上存在某些参数时,只需创建所需的查询。 (参数必须通过 GET 发送)

例如:

public function posts()
    $optional= array();

    if(!empty($this->params->query['status']))
                if(strlower($this->params->query['status']=='des'))
        $optional= array('Post.status DESC');
                

                else if(strlower($this->params->query['status']=='asc'))
                    $optional= array('Post.status ASC');
                
    

    if(!empty($this->params->query['department']))         
        //same...
    

    //order first by the sticky field and then by the optional parameters.
    $order = array('Post.stickyField DESC') + $optional;


    $this->paginate = array(
            'conditions' => $conditions,
            'order' => $order,
            'paramType' => 'querystring',

    );

    $this->set('posts', $this->paginate('Post'));

我使用了类似的东西来过滤一些数据,使用$conditions而不是$order,效果很好。

【讨论】:

感谢您的宝贵时间,但问题是我希望“粘性”字段对用户 100% 透明。他们永远不能让粘性物品排在第一位。它不应出现在 URL 或任何内容中,但排序链接和页面链接仍应正常工作。 您可以在我发布的代码中使用您的“粘性”字段,它将对最终用户完全透明。其余的排序,因为它与 CakePHP 排序一起使用,一如既往地通过 URL 可见。 我已经对其进行了编辑,以便始终按粘性字段和可选的 URL 参数对其进行排序。 不应该=='des' 实际上是=='desc'?另外,您是否测试过您的代码以验证排序链接和页面链接是否仍然正常工作? 是的。它应该是 desc。我的错。是的,它运作良好。正如我告诉你的,我让它与可选的 $conditions 一起工作。不要忘记在分页数组中使用 'paramType' => 'querystring'。【参考方案3】:

您可以使用自定义字段对分页组件进行排序和更新。

控制器代码

$order['Document.DATE'] = 'asc';

        $this->paginate = array(

                "conditions"=> $conditions ,
                "order" => $order ,
                "limit" => 10,
            **"sortcustom" => array('field' =>'Document.DATE' , 'direction' =>'desc'),**

            );

分页组件的变化。

公共函数 validateSort($object, $options, $whitelist = array())

    if (isset($options['sort'])) 
        $direction = null;
        if (isset($options['direction'])) 
            $direction = strtolower($options['direction']);
        
        if ($direction != 'asc' && $direction != 'desc') 
            $direction = 'asc';
        
        $options['order'] = array($options['sort'] => $direction);
    

    if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) 
        $field = key($options['order']);
        if (!in_array($field, $whitelist)) 
            $options['order'] = null;
        
    

    if (!empty($options['order']) && is_array($options['order'])) 
        $order = array();
        foreach ($options['order'] as $key => $value) 
            $field = $key;
            $alias = $object->alias;
            if (strpos($key, '.') !== false) 
                list($alias, $field) = explode('.', $key);
            

            if ($object->hasField($field)) 
                $order[$alias . '.' . $field] = $value;
             elseif ($object->hasField($key, true)) 
                $order[$field] = $value;
             elseif (isset($object->$alias) && $object->$alias->hasField($field, true)) 
                $order[$alias . '.' . $field] = $value;
            
        


        **if(count($options['sortcustom']) > 0 )
          
            $order[$options['sortcustom']['field']] = $options['sortcustom']['direction']; 
          **


        $options['order'] = $order;
    

    return $options;

【讨论】:

【参考方案4】:

轻松插入 'paramType' => 'querystring', 显示代码示例:

$this->paginate = array(
    'conditions' => $conditions,
    'order' => array(
        'Post.name' => 'ASC',
        'Post.created' => 'DESC',

    ),
    'paramType' => 'querystring',

);

$this->set('posts', $this->paginate('Post'));

【讨论】:

以上是关于CakePHP 分页:如何按多列排序以实现“粘性”功能?的主要内容,如果未能解决你的问题,请参考以下文章

带有连接表字段排序的 Cakephp 分页不起作用

CakePHP 3:多订单导致分页?

Django:如何编写查询以使用多列进行排序,通过模板显示

CakePHP 3.0 中虚拟字段/实体属性上的分页排序链接

SQL按多列以不同顺序排序后选择奇数行

Jquery排序分页插件tablesorter简介