В моей модели Order у меня есть следующий метод для суммирования общей стоимости 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'];
}
В моем действии представления OrderController я вызываю этот метод и устанавливаю значение для отправки в представление.
В представлении индекса моего заказа я вижу такие ссылки Paginator для запеченных полей.
<th><?php echo $this->Paginator->sort('user_id'); ?></th>
Но, насколько я понимаю, параметр для сортировки должен быть фактическим полем модели. Есть ли способ использовать этот помощник Paginator для разбивки на страницы с помощью моего собственного метода? Или есть способ использовать мой метод в качестве виртуального поля в моей модели Order?
Обновление. Я добавил в свою модель заказа следующий пользовательский метод поиска.
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;
}
затем я добавил следующее в представление индекса заказа
$this->paginate = array(
'findType' => 'withTotal'
);
перед звонком $this->paginate('Order')
. Теперь я могу прочитать значение $order['Order']['order_total']
в моем представлении, но когда я нажимаю ссылку $this->Paginator->sort('order_total')
, он обновляет параметр в URL-адресе, но не сортирует строки.
Обновите 2 РЕШЕНИЕМ
Чтобы исправить проблему сортировки, я реализовал следующий метод разбиения на страницы в моем контроллере заказа.
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;
}
Мне также пришлось добавить пустое виртуальное поле с именем order_total, чтобы пройти проверку сортировки нумерации страниц.
public $virtualFields = array(
'order_total' => '\'\''
);