Ссылка сортировки по страницам на виртуальное поле / свойство сущности в CakePHP 3.0


Я хочу создать ссылку сортировки по страницам на виртуальное поле/свойство сущности в CakePHP 3.0.

В CakePHP 2.x я использовал для создания виртуального поля , а затем создал ссылку сортировки по страницам на этом поле. Однако в CakePHP 3.0, виртуальные поля были заменены на свойства виртуальных сущностей.

Есть ли способ заставить это работать в CakePHP 3.0?

В моей ситуации у меня есть столбец first_name и last_name, который объединяются как full_name в свойствевиртуальной сущности . Я хочу отсортировать по full_name.

2   7  

2 ответа:

Как указано в связанных документах, виртуальные свойства не могут использоваться в находках. То есть по замыслу, виртуальные свойства живут только в сущностях, они строятся в PHP после того, как данные были извлечены из базы данных.

Поэтому давайте на время забудем о виртуальных свойствах и сосредоточимся на запросах и вычисляемых столбцах.

Вычисляемые столбцы должны быть заданы через sortWhitelist

Так же, как и столбцы связанных моделей, вычисляемые столбцы должны быть указаны в sortWhitelist вариант для того, чтобы быть пригодным для сортировки!

Поваренная книга > контроллеры > компоненты > разбиение на страницы > управление полями, используемыми для заказа

Через параметры пагинации

Здесь у вас есть некоторые опции, например, вы можете определить вычисляемые столбцы в параметрах разбиения на страницы:

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'fields' => [
        'id',
        'first_name',
        'last_name',
        'full_name' => $this->Table->query()->func()->concat([
            'first_name' => 'literal',
            'last_name' => 'literal'
        ]),
        // ...
    ],
    'order' => [
        'full_name' => 'DESC'
    ]
];

Пользовательский искатель

Другой, более многоразовый вариант-использовать пользовательский finder:

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'finder' => 'withFullName',
    'order' => [
        'full_name' => 'DESC'
    ]
];
public function findWithFullName(\Cake\ORM\Query $query, array $options)
{
    return $query->select([
        'id',
        'first_name',
        'last_name',
        'full_name' => $query->func()->concat([
            'first_name' => 'literal',
            'last_name' => 'literal'
        ]),
        // ...
    ]);
}

Отдельный пользовательский запрос

Также можно напрямую передавать объекты запроса в Controller::paginate():

$this->paginate = [
    // ...
    'sortWhitelist' => [
        'id',
        'first_name',
        'last_name',
        'full_name',
        // ...
    ],
    'order' => [
        'full_name' => 'DESC'
    ]
];

$query = $this->Table
    ->find()
    ->select(function (\Cake\ORM\Query $query) {
        return [
            'id',
            'first_name',
            'last_name',
            'full_name' => $query->func()->concat([
                'first_name' => 'literal',
                'last_name' => 'literal'
            ]),
            // ...
        ];
    });
$results = $this->paginate($query);

Установите порядок сортировки по умолчанию таким же, как и в виртуальном поле:

public $paginate = [
  'order' => [
    'first_name' => 'ASC',
    'last_name' => 'ASC',
  ]
];

Затем просто добавьте следующее в ваше представление, чтобы предотвратить переопределение пагинатором порядка по умолчанию, если он не указан пользователем:

if (empty($_GET['direction'])) { $this->Paginator->options(['url' => ['direction' => null, 'sort' => null]]); }