ndru
ndru

Reputation: 93

How to use route elements instead of query string arguments for pagination in CakePHP 4.x?

My website's pagination urls worked like this, but stopped working when i upgraded to 4.x - for example: 1st page: mywebsite.com/new - 2nd page: mywebsite.com/new/page/2, etc. I did that with the following code:

//routes.php        
$routes->connect('/new/page/:page',
        ['controller' => 'Articles', 'action' => 'latest'], [
        'pass' => [
            'page'
        ],
        'page' => '\d+'
    ]);
$routes->connect('/new', ['controller' => 'Articles', 'action' => 'latest']);

then in my view/pagination-element I have the following:

//view   
$this->Paginator->options(['url' => ['controller' => 'Articles', 'action' => 'latest']]);

The URLs mywebsite.com/new/page/2, 3, etc. are still working when accessing them directly, but links created through the paginator in the view are mywebsite.com/new?page=2, 3, etc. when they should be mywebsite.com/new/page/2, 3, etc.

can someone point me in the right direction?

Upvotes: 1

Views: 285

Answers (1)

ndm
ndm

Reputation: 60463

I'd suggest that you consider possibly changing your URL schema to use the query argument style. Using route/URI elements just means more work to get the paginator features working properly. Also all the arguments (SEO, readability, etc) made for using "pretty URLs" for pagination, that were so popular back in the days, turned out to be nothing but hot air.

That being said, you'd have to use a custom/extended paginator helper to change how URLs are being generated, as by default the helper will explicitly set the page parameter (and all other pagination related parameters) as query string arguments. You have control over all generated URLs if you override \Cake\View\Helper\PaginatorHelper::generateUrlParams().

A quick and dirty example:

// src/View/Helper/PaginatorHelper.php

/*
Load in `AppView::initialize()` via:

$this->loadHelper('Paginator', [
    'className' => \App\View\Helper\PaginatorHelper::class
]);
*/

declare(strict_types=1);

namespace App\View\Helper;

class PaginatorHelper extends \Cake\View\Helper\PaginatorHelper
{
    public function generateUrlParams(array $options = [], ?string $model = null, array $url = []): array
    {
        $params = parent::generateUrlParams($options, $model, $url);

        if (isset($params['?']['page'])) {
            $params[0] = $params['?']['page'];
            unset($params['?']['page']);
        } else {
            $params[0] = 1;
        }

        return $params;
    }
}

That would move to the page parameter value in the URL array from the query string config to a regular URL parameter, ie turn

['controller' => 'Articles', 'action' => 'latest', '?' => ['page' => 1, /* ... */]]

into

['controller' => 'Articles', 'action' => 'latest', 1, '?' => [/* ... */]]

But again, I'd strongly suggest considering to switch to the query string URL schema.

See also

Upvotes: 1

Related Questions