Here is how I am trying to paginate:
$posts = Post::all()->sortByDesc("created_at")->pagination(1);
But I get this error:
Method Illuminate\Database\Eloquent\Collection::pagination does not exist.
Here is how I am trying to paginate:
$posts = Post::all()->sortByDesc("created_at")->pagination(1);
But I get this error:
Method Illuminate\Database\Eloquent\Collection::pagination does not exist.
It is because paginate
is a Builder
method, not a collection.
You need to create paginator manually. How is described on Manually Creating A Paginator.
Creating a helper class
<?php
namespace App\Helpers;
use Illuminate\Container\Container;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
class PaginationHelper
{
public static function paginate(Collection $results, $showPerPage)
{
$pageNumber = Paginator::resolveCurrentPage('page');
$totalPageNumber = $results->count();
return self::paginator($results->forPage($pageNumber, $showPerPage), $totalPageNumber, $showPerPage, $pageNumber, [
'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'
));
}
}
Open the composer.json file. After want to add a helpers file. Composer has a files key (which is an array of file paths) that you can define inside of autoload:
"autoload": {
"files": [
"app/Helpers/PaginationHelper.php"
],
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/"
}
},
Now you have to type this command in the terminal:
composer dump-autoload
Now you can create a paginate of collections like the example below:
Route::get('/test_collect_pagintae', function () {
$users = \App\User::get();
$showPerPage = 20;
$paginated = PaginationHelper::paginate($users, $showPerPage);
return $paginated;
});
$options
and how could I use it? –
Ent It is because paginate
is a Builder
method, not a collection.
You need to create paginator manually. How is described on Manually Creating A Paginator.
You can use this code in app/provider/serviceProvider
in method boot:
Collection::macro('paginate', function($perPage, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage), // $items
$this->count(), // $total
$perPage,
$page,
[ // $options
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
This is very good solution from simonhamp. Thanks simonhamp
My suggestion is execute ->values() in AppServiceProvider like this below. It is important because when slicing a collection, keys are preserved, and we don't want that for paginator.
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$total ? $this : $this->forPage($page, $perPage)->values(),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
You can paginate easily by removing all:
$posts = Post::sortByDesc("created_at")->pagination(1);
In my case, I have to merge multiple collections and then paginate through the merged data, so I have to do something like this:
$items = $items2->merge($items1);
$items = $this->paginate($items);
public function paginate($items, $perPage = 15, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
Reference: Laravel Documentation, How to paginate Laravel collection?
Try this code:
//convert to array
$posts = Post::all()->sortByDesc("created_at")->toArray();
//Create new pagination
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$perPage = 3;
$currentItems = array_slice($posts, $perPage * ($currentPage - 1), $perPage);
//with path of current page
$posts = (new LengthAwarePaginator($currentItems, count($posts ), $perPage, $currentPage))->setPath(route('posts....'));
//Convert array of array to array of object
$posts->each(function ($item, $itemKey) use($posts) {
$posts[$itemKey] = (Object)$item;
});
© 2022 - 2024 — McMap. All rights reserved.
Post::latest()->paginate(1)
no need to load all the records into a collection to then return 1 of them – Pika