Laravel provides pagination out of the box for Eloquent Collections, but you can't use that by default on ordinary Collections.
Collections do have the forPage()
method, but it's more low-level, so it doesn't generate pagination links.
So you have to create a LengthAwarePaginator instance. But what if you want the behaviour to be the same as an Eloquent collection? Then use this macro!
The benefit of this is that the syntax and output is almost identical to the Eloquent Collection paginate()
method and so it can (relatively) easily be swapped out for an Eloquent Collection when testing.
Feel free to copy the most relevant code into your project. You're free to use and adapt as you need.
There are 2 approaches below. Which one you use is up to you, but you don't need both. I personally prefer the macro method as I feel it's cleaner and works well with minimal effort, but it's not so good at working with your IDE (code hints etc) and can feel a little detached in some cases.
If you prefer, add the Collection
macro to a Service Provider. That way you can call paginate()
on any collection:
collect([ ... ])->paginate( 20 );
See AppServiceProvider.php
for a sample implementation.
Where you want a "pageable" collection that is distinct from the standard Illuminate\Support\Collection
, implement a copy of Collection.php
in your application and simply replace your use Illuminate\Support\Collection
statements at the top of your dependent files with use App\Support\Collection
:
- use Illuminate\Support\Collection
+ use App\Support\Collection;
$collection = (new Collection([ ... ]))->paginate(20);
Note that this approach won't work with the collect()
helper function.
Spatie have create an awesome Composer package of loads of useful Collection macros. Go check it out!
Thanks @terremoth , you gave me ideas.
I managed to solve (so to have "/page/pagenumber" instead of "?page=pagenumber" in url and links) the way below.
As a reminder, I'm using the MACRO way.
First,
php artisan vendor:publish --tag=laravel-pagination
in this way you can find the blade section of the paginator in resources/views/vendor/pagination/
In my case (Laravel 7.2) i cloned the bootstrap-4.blade.php into andymnc.com.blade in the same folder.
Then edited the new blade file like this:
$paginator->previousPageUrl()
becomes:str_replace('?page=', '/page/',$paginator->previousPageUrl())
$element
instr_replace('?page=', '/page/',$element)
$url
instr_replace('?page=', '/page/',$url)
and
$paginator->nextPageUrl()
becomesstr_replace('?page=', '/page/',$paginator->nextPageUrl())
.Then, you have to make a route (in routes/web.php) to manage it. I did something like:
Route::get('/myroute/page/{page}', ['as' => 'myroute-page', 'uses' => 'MyController@index']);
In the MyController:
And finally I changed a little bit the AppServiceProvider.php made by @simonhamp
Maybe it can be done in a better way, anyway I hope it can help