Laravel: How to Paginate Collection
Photo by Markus Spiske on Unsplash
Laravel supports eloquent model pagination out of the box, but not custom collection. This quick tutorial will show you an easy way to paginate any collections.
Understanding how Laravel Paginator works
If we dive into Laravel’s query builder source code:
// Illuminate/Database/Eloquent/Builder.php
// ...
/**
* Paginate the given query.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*
* @throws \InvalidArgumentException
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$results = ($total = $this->toBase()->getCountForPagination())
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
I will briefly explain what Laravel is doing here line by line.
- Resolving the current page number in the query metadata.
- Resolving the chunking size ($perPage parameter).
- Splitting the query results into chunks and get the specific chunk/page that we are after.
- Generate a paginator response which includes the pagination metadata and result chunk.
As seen in step 3, Laravel collection class provides a sweet forPage()
method, which does the chunking and page retrieving for the paginator. Hmm…Let’s see if we can utilise that.
Creating a helper class
Let’s create our own collection helper class as shown below.
<?php
namespace App\Helpers\General;
use Illuminate\Container\Container;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
class CollectionHelper
{
public static function paginate(Collection $results, $total, $pageSize)
{
$page = Paginator::resolveCurrentPage('page');
return self::paginator($results->forPage($page, $pageSize), $total, $pageSize, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => 'page',
]);
}
/**
* Create a new length-aware paginator instance.
*
* @param \Illuminate\Support\Collection $items
* @param int $total
* @param int $perPage
* @param int $currentPage
* @param array $options
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
protected static function paginator($items, $total, $perPage, $currentPage, $options)
{
return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(
'items', 'total', 'perPage', 'currentPage', 'options'
));
}
}
I borrowed the paginator function from Laravel’s query builder class to return the same pagination response as Eloquent. Here’s what happening in our paginate method:
Resolve current page number in the query metadata.
We used the
forPage()
method to chunk the query results passed into the function. Then we return a pagination response with the other metadata, e.gtotal
,pageSize
and etc.That’s it. We can now use this helper function wherever in our app.
Usage
1. Sorting mutator
If you have included a mutator in your Eloquent model, you may want to sort query results by it. Eloquent doesn’t support mutator sorting, as mutator attributes are created after the query is completed. Good news is we can achieve this by leveraging our helper class that we just created.
Example:
Let’s say we have a full_name mutator in our customer model which combines first_name and last_name together. And we want to sort our query result by full_name. We can achieve this by:
// we use the sortBy method from collection class
$results = Customer::all()->sortBy('full_name');
$total = $results->count();
$pageSize = 20;
$paginated = CollectionHelper::paginate($results, $total, $pageSize);
2. Paginate non eloquent results
They could be merged results obtained from multiple API resources. This is especially common when we are integrating multiple app services together.
Let me know if you have any questions!
Posted from my Medium blog.
Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
https://medium.com/@sam_ngu/laravel-how-to-paginate-collection-8cb4b281bc55
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit