CakePHP - разбиение на страницы и сортировка ассоциаций 2-го уровня

Я понимаю, что об этом спрашивали 100000 раз, но я почти прочитал все 100000 ответов, и ни один из них, похоже, не соответствует тому, что мне нужно. Я перепробовал все возможные комбинации (очевидно, нет) и боюсь, что я проиграю в чем-то настолько относительно простом. Это мой второй проект Cake, так что я ни в коем случае не эксперт.

Профиль -> Принадлежит -> Магазин, Магазин -> Принадлежит -> Регион, Регион -> HasMany -> Магазины

Профиль .php

class Profile extends AppModel {  
public $belongsTo = array(
            'Store' => array(
                'className' => 'Store',
                'foreignKey' => 'store_id'....

Магазин .php

class Store extends AppModel {
public $belongsTo = array(
        'Region' => array(
            'className' => 'Region',
            'foreignKey' => 'region_id'....

Регион .php

class Region extends AppModel {
public $hasMany = array(
        'Store' => array(
            'className' => 'Store',
            'foreignKey' => 'region_id'....

ProfileController .php

$this->Paginator->settings = array(
    'conditions' => array('Profile.job_title_id' => '1'),
    'contain' => array(
        'Store'=> array(
            'Region'
        )
    )
);
$UserArds = $this->Paginator->paginate('Profile');
$this->set(compact('UserArds'));

просмотр .php

<th><?php echo $this->Paginator->sort('Region.name', 'Region'); ?></th>

Все, что я хочу сделать, это иметь возможность сортировать по названию региона при использовании пагинатора. Независимо от того, какую комбинацию я использую, я просто не могу отсортировать Region.name. Предложение order By опущено со всеми другими двухуровневыми ассоциациями, но отлично работает в любое другое время (с тем же уровнем или 1-м уровнем).

Может ли кто-нибудь предложить исправление этой простой ошибки?


person Kingsley    schedule 23.09.2013    source источник


Ответы (2)


Посмотрите на вывод отладки SQL, регионы извлекаются с помощью отдельных запросов, вот как сейчас работает Cakes ORM.

В вашем случае есть относительно простой обходной путь. Просто создайте правильный ассоциация на лету, например Profile belongsTo Region.

Вот (непроверенный) пример, он добавляет ассоциацию belongsTo с параметром foreignKey, установленным на false, чтобы отключить автоматическую генерацию внешнего ключа ORM, это необходимо, поскольку в противном случае он будет искать что-то вроде Profile.region_id. Обратите внимание, что, следовательно, конфигурация contain тоже должна быть изменена!

$this->Profile->bindModel(array(
    'belongsTo' => array(
        'Region' => array(
            'foreignKey' => false,
            'conditions' => array('Region.id = Store.region_id')
        ),
    )
));

$this->Paginator->settings = array(
    'conditions' => array('Profile.job_title_id' => '1'),
    'contain' => array('Store', 'Region')
);

Это должно сгенерировать правильный запрос, который включает в себя stores, а также regions таблицу, что позволит выполнить сортировку по Region.name. Обратите внимание, что результирующий массив будет немного отличаться, Region не будет вложен в Store, все будет размещено на одном уровне, то есть:

Array
(
    [Profile] => Array
        (
            ....
        )

    [Store] => Array
        (
            ....

        )

    [Region] => Array
        (
            ....

        )
)

Вы либо соответствующим образом изменяете код представления, либо трансформируете извлеченные данные перед их передачей в представление. Третий вариант - включить вложенный Region в конфигурацию contain, однако это приведет к дополнительным запросам, которые совершенно не нужны, поскольку данные уже были получены с основным запросом, поэтому я бы не рекомендовал этого.

person ndm    schedule 23.09.2013
comment
Это был фантастический друг! Сработало как лакомство. Хотя я пробовал это раньше, я думаю, что делал это неправильно. Теперь это определенно поможет на протяжении всего проекта. Ваше здоровье! - person Kingsley; 24.09.2013

Отличный ответ. Я использовал это. Чтобы попытаться обобщить его для других пользователей:

$this->FirstLevel->bindModel(array(
    'belongsTo' => array(
        'SecondLevel' => array(
            'foreignKey' => false,
            'conditions' => array('SecondLevel.firstLevel_id = FirstLevel.id')
        ),
    )
));

$this->Paginator->settings = array(
    //'conditions' => $retrieveDataCondition,
    'contain' => array('SecondLevel')
);
$data = $this->Paginator->paginate('FirstLevel');
person Britc    schedule 01.11.2015