Unexpected result when rendering pages of paginator

Hello you,
I would like to add the Laminas Paginator to my site. I have a database with a lot of data and I want to get on page 1 only the first 5 database entries, on page 2 only the entries from 6-10 and so on. This works so far. In my test version I have 22 entries. That makes a total of 5 pages. Now I am only shown page 1 with the first 5 entries, but no possibility to click on page 2. I get the maximum entries (22) and divide them by 5, which gives me the total number of pages (5). But since only 5 entries are ever loaded, it also only shows one page with 5 entries.

I would like to set the total page count. I tried that with $paginator->setPageRange(ceil($maxPageNumber)); but it doesn’t work. When debugging it comes up with the correct numbers but in the frontend it only shows one page.
onlyOnePage
Like you see in the picture it is only one. My wish is, that it shows 5. and when I click on 2, then the next five entries are loaded.

Can someone help me?

In my test version

Can you share the automated test+sources where you get to this rendered output, please? I think that’s not how the rendering is supposed to work, so it is likely that you applied a limit on the selection, instead of passing a full paginator to the view renderer.

hey, thanks a lot for the quick answer. this is my handle function in the email-search-handler.
the “findAllPaginated” gives me only 5 mails. so this could be the issue. I thought I could still output the number of pages based on the total number of entries.

 /**
     * @param ServerRequestInterface $request
     * @return ResponseInterface
     */
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        (int)$pageNumber = array_key_exists('page', $request->getQueryParams()) ? $request->getQueryParams()['page'] : 1;

        $firstEmailIdOnPage = $pageNumber === 1 ? 1 : $pageNumber * self::ITEM_COUNT_PER_PAGE;
        $emailsPaginated = $this->emailRepository->findAllPaginated($firstEmailIdOnPage);

        $maxNumOfEmails = $this->emailRepository->countAllEmails();
        (int)$maxPageNumber = $maxNumOfEmails / self::ITEM_COUNT_PER_PAGE;

        $paginator = new Paginator(
            new ArrayAdapter($emailsPaginated)
        );

        $paginator->setCurrentPageNumber((int)$pageNumber);
        $paginator->setPageRange(ceil($maxPageNumber));

        return new HtmlResponse(
            $this->renderer->render('emails::search', [
                'paginator' => $paginator,
                'emails' => $emailsPaginated,
            ])
        );
    }

and in the html:

 <?= $this->paginationControl(
        $this->paginator,
        'sliding',
        'partials::paginator'
    ) ?>

Hey,


|
|

  • | - |

        $emailsPaginated = $this->emailRepository->findAllPaginated($firstEmailIdOnPage);

        $maxNumOfEmails = $this->emailRepository->countAllEmails();

        (int)$maxPageNumber = $maxNumOfEmails / self::ITEM_COUNT_PER_PAGE;

        $paginator = new Paginator(

            new ArrayAdapter($emailsPaginated)

        );

The fact that $emailsPaginated is an array here indicates that your ArrayAdapter is probably really only 5 elements big.
In practice, the paginator is correct in rendering only one page: that’s all you gave to it, and it correctly thinks that there is only one page.

The usual approach to this would be to construct a paginator with all the results in it (lazy or eager, depending on backing data size/structure), and then letting the paginator decide which page it is supposed to show.

To try it out, $emailsPaginated contained 1000 elements, the rendering would be different: give it a shot.

cool thanks! that sounds clear. the main problem is that in the right setting all emails have huge attachments and this find all method is therefore not “must” be used. so I don’t know if what I want is even possible (total number of pages with simultaneous fetching of only 5 entries)

Hello and welcome to our forums! :smiley:

If you use laminas-db, you can use the DbSelect adapter and only the records for the current page will be fetched.

Another option is to use a custom adapter. Example:

class FixedAdapter implements Laminas\Paginator\Adapter\AdapterInterface
{
    private iterable $items;

    private int $count;

    public function __construct(iterable $items = [], int $count = 0)
    {
        $this->items = $items;
        $this->count = $count;
    }

    public function getItems($offset, $itemCountPerPage): iterable
    {
        return $this->items;
    }

    public function count(): int
    {
        return $this->count;
    }
}

Usage:

$paginator = new Laminas\Paginator\Paginator(
    new FixedAdapter($emailsPaginated, $maxNumOfEmails)
);
$paginator->setItemCountPerPage(15);
$paginator->setCurrentPageNumber($pageNumber);

This must be: $pageNumber = (int)'…';

thank you @froschdesign ; I will check this out!!

thanks you all, it worked perfectly

What do you use now? DbSelect or FixedAdapter?

I use FixedAdapter! This works fine.