Skip to content

Paginator with out of bounds fix

Mark Scherer edited this page Dec 5, 2023 · 5 revisions

Note: For CakePHP 3/4, For CakePHP 5+ see https:/dereuromark/cakephp-shim/releases/tag/3.2.0

Drop this into your src/Controller/Component folder and it will work out of the box:

<?php

namespace App\Controller\Component;

use Cake\Controller\Component\PaginatorComponent as CorePaginatorComponent;
use Cake\Datasource\QueryInterface;
use Cake\Http\Exception\NotFoundException;

class PaginatorComponent extends CorePaginatorComponent
{
    /**
     * Overwrite to always redirect from out of bounds to last page of paginated collection.
     * If pageCount not available, then use first page.
     *
     * @param \Cake\Datasource\RepositoryInterface|\Cake\Datasource\QueryInterface $object The table or query to paginate.
     * @param array $settings The settings/configuration used for pagination.
     *
     * @throws \Cake\Http\Exception\NotFoundException
     *
     * @return \Cake\Datasource\ResultSetInterface Query results
     */
    public function paginate($object, array $settings = [])
    {
        try {
            $resultSet = parent::paginate($object, $settings);
        } catch (NotFoundException $exception) {
            $query = null;
            if ($object instanceof QueryInterface) {
                $query = $object;
                $object = $query->repository();
            }
            $alias = $object->alias();
            $lastPage = $this->request->params['paging'][$alias]['pageCount'] > 1 ? $this->request->params['paging'][$alias]['pageCount'] : null;

            $response = $this->getController()->redirect(['?' => ['page' => $lastPage] + $this->request->getQuery()]);

            // To be please PHPCS and tests, cannot be reached in production.
            if (PHP_SAPI === 'cli') {
                throw new NotFoundException('Redirect to ' . $response->getHeaderLine('Location') . ' for non-CLI.');
            } else {
                $response->send();
            }

            exit();
        }

        return $resultSet;
    }
}

Why is this a snippet

and not as class directly in Shim plugin etc?

You might want to add a custom $this->Flash->error() for this case, or you want to log this as well. So having this as copy and paste for your app allows easier customization for the time being.

Clone this wiki locally