Welcome Guest, Not a member yet? Register   Sign In
Support for 'perPage' Parameter in Pager Library
#1

Hello,

I've been working with the Pager library in CodeIgniter 4 and noticed that while it automatically handles the `page` parameter from the URL query string, it doesn't provide similar functionality for the number of items per page.

Current Behavior

Currently, the Pager class automatically reads the `page` parameter from the URL (e.g., `?page=5`), but the number of items per page (`perPage`) must be manually specified in the code:

PHP Code:
// Controller method
public function index()
{
    $model = new MyModel();
    $data = [
        'items' => $model->paginate(20), // perPage hardcoded as 20
        'pager' => $model->pager
    
];
    return view('my_view'$data);



Proposed Enhancement

I'd like to propose adding support for a `perPage` parameter in the URL query string, similar to how the `page` parameter works. This would allow clients to specify how many items they want per page directly in the URL:

Code:
/users?page=5&perPage=50


The Pager library would automatically detect this parameter and use it instead of the default value or the one specified in the code.

Benefits

1. Improved API Development: This would make the Pager more suitable for RESTful API development, where clients often need to control the pagination parameters.
2. Consistent Interface: It would provide a consistent interface for both page number and page size parameters.
3. Reduced Boilerplate: Developers wouldn't need to manually check for and apply the `perPage` parameter in every controller method.
4. Better User Experience: Frontend applications could allow users to choose how many items they want to see per page.

Implementation Suggestion

The implementation could be similar to how the `page` parameter is handled in the `calculateCurrentPage()` method, with appropriate safety checks to ensure the value is within acceptable limits:

PHP Code:
// Inside the Pager class
protected function calculatePerPage(string $group)
{
    $perPageSelector 'perPage'// or configurable
   
    
if (isset($_GET[$perPageSelector])) {
        $perPage = (int) $_GET[$perPageSelector];
        $minPerPage 1;
        $maxPerPage $this->config->maxPerPage ?? 100;
       
        $this
->groups[$group]['perPage'] = max($minPerPagemin($perPage$maxPerPage));
    }



This would respect the existing API while adding the new functionality in a backward-compatible way.

Has anyone else found this limitation? Would this feature be valuable to the community?

Thank you for considering this enhancement!
Reply
#2

We can simply do
PHP Code:
$model->paginate($this->request->getGet('perPage')); // previously validating this value 

IMO this is quite easy to implement when we need this kind of feature, but I'm not against improvements.
Reply
#3

Yeah but i mentioned it at point 3 of Benefits:

3. Reduced Boilerplate: Developers wouldn't need to manually check for and apply the `perPage` parameter in every controller method.
Reply
#4

Fair enough. As I said - I'm not against improvements.
Reply
#5

You can reduce the boilerplate by creating this functionality in the BaseController if you so desire, you don't have to add it to every controller if you extend from there.
Reply
#6

(This post was last modified: 03-31-2025, 05:19 AM by campio97.)

I extended the model by creating a new function based on the original paginate method, with the addition of support for the $perPageFromQuery parameter. I also introduced a new property in the model, $perPageMaxLimit, which allows setting a default maximum number of items per page. This makes it possible to define pagination limits on a per-model basis, rather than relying solely on a global setting.
PHP Code:
/**
 * Retrieves a paginated set of results using the Pager service.
 *
 * This method calculates the proper limit and offset for paginated queries based on several sources:
 * - A GET parameter (`?page=2`) to select the current page.
 * - An optional GET parameter (`?perPage=n`) to dynamically adjust the number of items per page.
 * - Direct method parameters to override default values if necessary.
 *
 * Additionally, the maximum allowed items per page can be configured per model via the
 * `$perPageMaxLimit` property.
 *
 * @param int|null $perPage  The desired number of items per page. Or use the GET parameter.
 * @param string  $group    Identifier for the pagination set; useful when multiple paginations are in use.
 * @param int|null $page    Optional page number (useful when provided via an alternative mechanism).
 * @param int      $segment  Optional URI segment index to extract the page number if applicable.
 *
 * @return array|null Returns the paginated result set, or null if no records are found.
 */
public function paginateApi(?int $perPage nullstring $group 'default', ?int $page nullint $segment 0)
{
    // Retrieve the shared Pager service, which might be used by several models.
    $pager service('pager');

    // If a specific URI segment is provided, update the Pager accordingly.
    if ($segment !== 0) {
        $pager->setSegment($segment$group);
    }

    // Check if the GET parameter 'perPage' is provided and use it if $perPage is not already defined.
    $request service('request');
    $perPageFromQuery $request->getGet('perPage');

    if ($perPageFromQuery !== null && !$perPage) {
        $perPage = (int) $perPageFromQuery;

        // Enforce security limits for the number of items per page (adjust the min/max values as needed).
        $minPerPage 1;
        $maxPerPage $this->perPageMaxLimit ?: $perPage;
        $perPage max($minPerPagemin($perPage$maxPerPage));
    }

    // Determine the current page: use the provided $page if valid, otherwise retrieve it from the Pager.
    $page $page >= $page $pager->getCurrentPage($group);

    // Store the pagination settings in the Pager, making them accessible in the views.
    $this->pager $pager->store($group$page$perPage$this->countAllResults(false), $segment);
    $perPage $this->pager->getPerPage($group);
    $offset  = ($pager->getCurrentPage($group) - 1) * $perPage;

    // Return the paginated results.
    return $this->findAll($perPage$offset);

Reply




Theme © iAndrew 2016 - Forum software by © MyBB