分页时,在分页时不能使用自定义模型查找

时间:2013-07-16 07:53:45

标签: cakephp cakephp-2.3

我在用户模型中自定义查找类型方法:

protected function _findStats($state, $query, $results = array()) {
    if ($state === 'before') {
        debug($query);
        $query['fields'] = array('User.id', 'User.username', 'Click.clicks', 'Click.unique', 'Sale.sales_1', 'Sale.sales_2');
        $query['joins'] = array(
            array(
                'table' => '(' . $this->__buildSubQueryClicks() . ')',
                'alias' => 'Click',
                'type' => 'LEFT',
                'conditions' => array('User.id = Click.id')
            ),
            array(
                'table' => '(' . $this->__buildSubQuerySales() . ')',
                'alias' => 'Sale',
                'type' => 'LEFT',
                'conditions' => array('User.id = Sale.id')
            )
        );
        return $query;
    }
    return $results;
}

现在来自其他Controller(名为ReportsController)我想对此查找的结果进行分页。我是这样做的:

public function admin_index() {     
    list($from, $to) = $this->_prepareCommonVariables();
    $this->paginate = array('stats');
    $this->User->recursive = 0;
    $this->set('users', $this->paginate('User',
        array(
            'Click.created BETWEEN ? AND ?' => array($from, $to),
            'Sale.sold BETWEEN ? AND ?' => array($from, $to)
        ),
        array('User.username', 'Click.unique', 'Click.clicks', 'Sale.sales_1', 'Sale.sales_2')
    ));
}

问题是我只能按User.idUser.username字段(通常是用户字段)排序。即使我通过Controller::paginate()的第三个参数指定了允许的字段,它也不起作用。 Paginator Helper链接会生成正确的URL(例如/admin/reports/index/sort:Click.clicks/direction:asc),但我在SQL查询中看不到ORDER BY部分。我已将debug($query)放入_findStats(),当字段为Click.clicks时,$query['order']为空。

2 个答案:

答案 0 :(得分:1)

好的,我发现$ query也会回复'sort'和'direction'键。所以,这里是解决方案:

protected function _findStats($state, $query, $results = array()) {
    if ($state === 'before') {
        $query['fields'] = array('User.id', 'User.username', 'Click.clicks', 'Click.unique', 'Sale.sales_1', 'Sale.sales_2');
        $query['joins'] = array(
            array(
                'table' => '(' . $this->__buildSubQueryClicks() . ')',
                'alias' => 'Click',
                'type' => 'LEFT',
                'conditions' => array('User.id = Click.id')
            ),
            array(
                'table' => '(' . $this->__buildSubQuerySales() . ')',
                'alias' => 'Sale',
                'type' => 'LEFT',
                'conditions' => array('User.id = Sale.id')
            )
        );
        if (isset($query['sort'], $query['direction'])) {
            $query['order'] = array($query['sort'] => $query['direction']);
        }
        return $query;
    }
    return $results;
}

当然这不是安全的解决方案,因为它省略了PaginatorComponent::validateSort()

答案 1 :(得分:0)

按不存在的字段排序

从问题中的代码 - 看起来你已经做了正确的事情。

分页器组件validates the sort order,如果它来自请求:

  

验证是否可以对$ object执行所需的排序。只有字段或   virtualFields可以进行排序。方向参数也将被消毒。最后   sort +方向键将转换为模型友好的订单键。

     

您可以使用白名单参数来控制哪些列/字段可用于排序。   这有助于防止用户在未编入索引的值上排序大型结果集。

如问题所示,传递白名单应允许跳过此逻辑,但如果不调试,则可能 }和$field中的值。

明确作品

请记住问题中的调用是管理路由 - 您可以放弃验证排序参数的“安全性”,只需从请求中明确设置排序顺序:

$whitelist