saloonphp / saloon

🤠 Build beautiful API integrations and SDKs with Saloon
https://docs.saloon.dev
MIT License
2.09k stars 107 forks source link

Pagination: `currentPage` doesn't align with `page` #432

Closed jorqensen closed 3 months ago

jorqensen commented 5 months ago

I stumbled across something rather annoying with the pagination plugin, perhaps I am misunderstanding something. Clarification would be appreciated.

I'm working with an API that uses limit and page for pagination, so I've set my pagination up as such:

protected function applyPagination(Request $request): Request
{
    $request->query()->add('page', $this->currentPage);

    if (isset($this->perPageLimit)) {
        $request->query()->add('limit', $this->perPageLimit);
    }

    return $request;
}

However, this means that my pagination will start at page 0 as currentPage is set to 0. Applying ->setStartPage() on the paginator doesn't do anything, neither does setting the currentPage property on my pagination class to 1.

Moving to the deprecated page property will make everything work as expected:

$request->query()->add('page', $this->page);

What's the idea for currentPage not starting at 1? Or how do you actually properly set the starting page to 1, without making use of the deprecated/internal property?

patrickcarlohickman commented 5 months ago

@jorqensen ,

The currentPage variable is used to track which page the paginator is currently on. When you start and haven't made any requests, the current page is 0 (or, startPage - 1, if you've set the start page). Once you request page 1, then the currentPage will advance to 1.

The applyPagination() method is called before requests to update the request to get the next page. Since you're trying to get the next page, and not the current page, you want to update the request with $this->currentPage + 1.

If you look at the applyPagination() method on the parent PagedPaginator class, you'll see it still uses the deprecated page property (which is equal to $this->currentPage + 1).

Since this property is deprecated, I tend to use $this->currentPage + 1 in my own custom paginators. Also, the $this->currentPage + 1 logic is used multiple times inside the parent Paginator class.

Sammyjo20 commented 4 months ago

Hey @jorqensen

As Patrick kindly mentioned, the page property does start at 1, but that meant that by the time it ran applyPagination, that value was actually 2, so I deprecated it and introduced currentPage which is the "correct" value. Patrick's suggestion above should be suitable to get pagination working.

craigpotter commented 3 months ago

Don't know if it will help but I found today that rewinding the Paginator will help with the setStartPage();


$paginator = $myConnector->paginate(new MyRequest()); 

$paginator->setStartPage(15);
$paginator->rewind(); 

foreach ($paginator as $page) {
    // code
} 
patrickcarlohickman commented 3 months ago

@craigpotter ,

You may want to test again to see what is going on. In your example, manually calling rewind() shouldn't have any effect, since the rewind() method is the first method that is automatically called by the foreach().

The paginator can be used in a foreach() because it implements the Iterator interface. You can see in the php docs the order that the iterator methods are called when it is used in a foreach(). The docs show the very first method call is to rewind(). The first iteration calls rewind() => valid() => current() => key(). Subsequent iterations call next() => valid() => current() => key(). The foreach stops when valid() returns false.

jorqensen commented 3 months ago

Thank you @patrickcarlohickman for the clear explanation and @Sammyjo20 for following up. Sorry I've been late to get back, I've been swarmed with stuff lately.

currentPage +1 does indeed fix my issue, why it had to be like this was a bit confusing and to some degree still is. Either way, no need to drag something on that isn't a bug. Thanks once again! 👌

EDIT: And thanks @craigpotter for chiming in as well. 👍