Pagination sort link on a virtual field/entity property in CakePHP 3.0

前端 未结 2 1443
灰色年华
灰色年华 2020-12-10 15:53

I want to create a pagination sort link on a virtual field/entity property in CakePHP 3.0.

In CakePHP 2.x I used to create a virtual field, and then create a paginat

相关标签:
2条回答
  • 2020-12-10 16:52

    Set your default sort order to be the same as your virtual field:

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

    Then just add the following to your View to prevent the paginator from overriding the default order unless specified by the user:

    if (empty($_GET['direction'])) { $this->Paginator->options(['url' => ['direction' => null, 'sort' => null]]); }
    
    0 讨论(0)
  • 2020-12-10 16:53

    As stated in the linked docs, virtual properties cannot be used in finds. That's by design, virtual properties only live in entities, they are built in PHP after data has been retrieved from the database.

    So let's forget about virtual properties for a moment, and concentrate on queries and computed columns.

    Computed columns need to be specified via sortWhitelist

    Just like columns of associated models, computed columns need to be specified in the sortWhitelist option in order to be useable for sorting!

    Cookbook > Controllers > Components > Pagination > Control which Fields Used for Ordering

    Via pagination options

    You have some options here, for example you could define computed columns in the pagination options:

    $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'
        ]
    ];
    

    A custom finder

    Another, more reusable option would be to use a custom 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'
            ]),
            // ...
        ]);
    }
    
    • Cookbook > Controllers > Components > Pagination > Using Controller::paginate()
    • Cookbook > ... ORM > Retrieving Data & Results Sets > Custom Finder Methods

    Separate custom query

    It's also possible to directly pass query objects to 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);
    
    0 讨论(0)
提交回复
热议问题