Пагинатация Cakephp на основе метода модели

В моей модели 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' => '\'\''
);

person Devin Crossman    schedule 19.08.2013    source источник


Ответы (1)


Прочтите это. Первый ключ массива - это метод поиска.

public $paginate = array(
    'popular'
);

Поскольку 0-м индексом сложно управлять, в 2.3 была добавлена ​​опция findType:

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

Также вместо paginate вы должны использовать настройки $ this-> Paginator-> в 2.3, похоже, что пример книги еще не обновлен.

person floriank    schedule 19.08.2013
comment
Спасибо .. Я почти у цели. Я получил пагинатор, чтобы использовать мой собственный метод поиска (который я добавил к своему вопросу), и теперь у меня есть $order['Order']['order_total'], доступный для печати, но когда я нажимаю ссылку сортировки $this->Paginator->sort('order_total'), он не сортируется по order_total, но добавляет sort:order_total к url - person Devin Crossman; 20.08.2013
comment
понял это .. спасибо, что указал мне в правильном направлении - person Devin Crossman; 20.08.2013