简体   繁体   English

基于模型方法的Cakephp分页

[英]Cakephp paginate based on model method

In my Order model I have the following method to sum the total price of the Order's OrderItems 在我的订单模型中,我有以下方法可对订单的OrderItems的总价求和

public function getTotalPrice($id = null) {
    if (!$this->exists($id)) {
        throw new NotFoundException(__('Invalid order'));
    }
    $total = $this->OrderItem->find('first', array(
        'conditions' => 'OrderItem.order_id = '.$id,
        'fields' => 'SUM('.$this->OrderItem->virtualFields['total_price'].') AS total',
        'group' => 'OrderItem.order_id'

    ));
    return $total[0]['total'];
}

In my OrderController's view action I am calling this method and the setting the value to send to the view. 在我的OrderController的视图操作中,我正在调用此方法并设置要发送到视图的值。

In my Order's index view I see Paginator links like this for the baked fields. 在我的订单的索引视图中,我看到了针对烘烤字段的分页器链接。

<th><?php echo $this->Paginator->sort('user_id'); ?></th>

But as I understand it, the parameter to sort needs to be an actual field on the model. 但据我了解,要排序的参数必须是模型上的实际字段。 Is there any way to use this Paginator helper to paginate with my custom method? 有什么方法可以使用此Paginator助手对我的自定义方法进行分页吗? Or is there a way to make my method be used as a virtual field on my Order model? 还是有一种方法可以将我的方法用作我的Order模型的虚拟字段?

Update I added the following custom find method on my Order model 更新我在我的订单模型上添加了以下自定义查找方法

public $findMethods = array('withTotal' =>  true);

protected function _findWithTotal($state, $query, $results = array()) {
    if ($state === 'before') {
        // make sure to fetch OrderItems
        if(!isset($query['contain'])) {
            $query['contain'] = 'OrderItem';
        } else if (is_array($query['contain'])) {
            if(!in_array('OrderItem', $query['contain'])) {
                array_push($query['contain'], 'OrderItem');
            }
        } else if(is_string($query['contain']) && strpos($query['contain'], 'OrderItem') === false) {
            $query['contain'] = array($query['contain'], 'OrderItem');
        }
        return $query;
    } else if ($state === 'after') {
        if(count($results) > 0) {
            foreach($results as &$order) {
                if(isset($order['OrderItem'])) {
                    $total = 0;
                    foreach($order['OrderItem'] as $orderItem) {
                        $total += $orderItem['total_price'];
                    }
                    $order['Order']['order_total'] = $total;
                }
            }
        }
    }
    return $results;
}

then I added the following to the Order's index view 然后我将以下内容添加到订单的索引视图中

$this->paginate = array(
    'findType' => 'withTotal'
);

before calling $this->paginate('Order') . 在调用$this->paginate('Order') Now I am able to read the value of $order['Order']['order_total'] in my view but when I click the $this->Paginator->sort('order_total') link it updates the parameter in the url but does not sort the rows. 现在,我可以在视图中读取$order['Order']['order_total'] ,但是当我单击$this->Paginator->sort('order_total')链接时,它将更新url中的参数但不对行进行排序。

Update 2 with SOLUTION 使用解决方案更新2

To fix the sorting problem I implemented the following paginate method in my Order controller 为了解决排序问题,我在Order控制器中实现了以下分页方法

public function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array()) {
    // get orders with total
    $contain = $extra['contain'];
    $orders = $this->find('withTotal', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group', 'contain'));
    // if sorting by order_total
    if(is_array($order) && array_key_exists('order_total', $order)) {
        $sortDirection = $order['order_total'];
        uasort($orders, function($a, $b) use($sortDirection) {
            if($a['Order']['order_total'] == $b['Order']['order_total']) {
                return 0;
            } else if($sortDirection == "asc") {
                return ($a['Order']['order_total'] > $b['Order']['order_total']) ? -1 : 1;
            } else if($sortDirection == "desc") {
                return ($a['Order']['order_total'] < $b['Order']['order_total']) ? -1 : 1;
            }
        });
    }
    return $orders;
}

I also had to add an empty virtual field named order_total to get the pagination sort validation to pass 我还必须添加一个名为order_total的空虚拟字段,以使分页排序验证通过

public $virtualFields = array( 
    'order_total' => '\'\''
);

Read this . 阅读此 First key of the array is the find method. 数组的第一个键是find方法。

public $paginate = array(
    'popular'
);

Since the 0th index is difficult to manage, in 2.3 the findType option was added: 由于第0个索引难以管理,因此在2.3中添加了findType选项:

public $paginate = array(
    'findType' => 'popular'
);

Also instead of paginate you should use $this->Paginator->settings in 2.3, looks like the book example is not up to date yet. 另外,您应该在2.3中使用$ this-> Paginator-> settings代替分页,看起来这本书的示例尚未更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM