Laravel 5.4 LengthAwarePaginator - laravel

My brain suddenly crashed on this one. Anyone care to help me is highly appreciated.
This is LengthAwarepaginator in laravel 5.4
Here is the code.
$collection = [];
foreach ($maincategories->merchantCategory as $merchantCat) {
foreach ($merchantCat->merchantSubcategory as $merchantSub) {
foreach($merchantSub->products as $products){
$collection[] = $products;
}
}
}
$paginate = new LengthAwarePaginator($collection, count($collection), 10, 1, ['path'=>url('api/products')]);
dd($paginate);
It displays perfectly but the problem is the items is 100. That's all my items and I specify it correctly. I need to display only 10.
Base on LengthAwarePaginator constructor. Here is the reference.
public function __construct($items, $total, $perPage, $currentPage = null, array $options = [])
Here is the screen shot.
Where did I go wrong? TY

When manually creating a paginator, you have to slice the result set yourself. The first parameter to the paginator should be the desired page of results, not the entire result set.
From the pagination documentation:
When manually creating a paginator instance, you should manually "slice" the array of results you pass to the paginator. If you're unsure how to do this, check out the array_slice PHP function.
I would suggest using a Collection to help out with this a little:
// ...
$collection = collect($collection);
$page = 1;
$perPage = 10;
$paginate = new LengthAwarePaginator(
$collection->forPage($page, $perPage),
$collection->count(),
$perPage,
$page,
['path' => url('api/products')]
);

For the heavy select and to avoid any multiple select to calculate the total from the table we unable to use model paginate
use Illuminate\Pagination\LengthAwarePaginator;
in your controller function
if(!isset($input["total"])){ //initial request
$total = //Find the total only one time.
$request->request->add(['total' => $total]); //Add it in the request so that we can print it in blade
}else
$total = $input["total"]; //After initial request
$currentPage = LengthAwarePaginator::resolveCurrentPage(); //page variable from GET or POST
$perPage = 30; //Page Length
$offset = ($currentPage - 1) * $perPage; //find the offset to pass in query
$specificRecords = /*Collect specific page records in array
if mysql then Select * from table limit $perPage offset $offset
if ms sql then OFFSET {$offset} ROWS FETCH NEXT {$perPage} ROWS ONLY */
$records = new LengthAwarePaginator($specificRecords,$total,$perPage,Null,[ "path" => "/pagepath" ]);
in blade:
<center>{{$records->appends(Request::except([ 'page','_token' ]))->links()}}</center>
Check Page and total variable in page tags ensure you added page in except list :)

Related

Eloquent paginate two relation merged

I have two models : Task and Comment
In my user profil I want to display tasks and comments sort by created date.
For this I do :
$timeline_array = $customer->comments;
$timeline_array = $timeline_array->toBase()->merge($customer->tasks);
//sort timeline event
$timeline_array = $timeline_array->sortByDesc(function($timeline_event){
return $timeline_event->created_at;
});
And I foreach my array in my view. It's work fine but if I have too much comments or tasks it's will be a big request so I want to add a paginator.
How can I do it ?
If I had a $timeline_array->paginate(5); at the end I get the error :
Method Illuminate\Support\Collection::paginate does not exist.
And I think it's not fixing my problem because I load all the comments and tasks before I paginate it.
Somebody have an idea/solution ?
Finally found a solution :
$timeline_array = $customer->comments;
$timeline_array = $timeline_array->toBase()->merge($customer->tasks);
//sort timeline event
$timeline_array = $timeline_array->sortByDesc(function($timeline_event){
return $timeline_event->created_at;
});
$item_per_page = 10;
$timeline_array = new LengthAwarePaginator($timeline_array->forPage(Paginator::resolveCurrentPage(), $item_per_page), count($timeline_array), $item_per_page, Paginator::resolveCurrentPage(), [
'path' => Paginator::resolveCurrentPath()
]);
Paginate method only works on a query builder or an eloquent ,
someone has created a gist over here where you can use paginate over an array or collection :
https://gist.github.com/vluzrmos/3ce756322702331fdf2bf414fea27bcb
Try using it like this :
$timeline_array = $customer->comments;
$timeline_array = $timeline_array->toBase()->merge($customer->tasks);
//sort timeline event
$timeline_array = $timeline_array->sortByDesc(function($timeline_event){
return $timeline_event->created_at;
});
$timeline_array = $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);
}
Or adding it as a Macro for collection in your App Service Provider for more better practice.

How to create a paginator?

I've checked out the rather thin docs, but still unsure how to do this.
I have a collection. I wish to manually create a paginator.
I think I have to do something like, in my controller:
new \Illuminate\Pagination\LengthAwarePaginator()
But, what params do I need and do I need to slice the collection? Also how do I then display the 'links' in my view?
Could someone post a simple example how to create a paginator?
Please note, I don't want to paginate eloquent, eg. User::paginate(10);
Take a look at the Illuminate\Eloquent\Builder::paginate method for an example on how to create one.
A simple example of doing one using an eloquent model to pull out the results etc:
$page = 1; // You could get this from the request using request()->page
$perPage = 15;
$total = Product::count();
$items = Product::take($perPage)->offset(($page - 1) * $perPage)->get();
$paginator = new LengthAwarePaginator(
$items, $total, $perPage, $page
);
The first parameter accepts the results to display on the page that you're on
the second is the total number of results (The total number of items you're paginating, not the total number of items you're displaying on that page)
the third is the number per page you want to display
the fourth is the page that you're on.
You can pass in extra options as a fifth parameter if you want to customise things as well.
The links you should just be able to generate using the ->render() or ->links() method on the paginator as you would if you used Model::paginate()
With an existing collection of items you could do this:
$page = 1;
$perPage = 15;
$total = $collection->count();
$items = $collection->slice(($page - 1) * $perPage, $perPage);
$paginator = new LengthAwarePaginator(
$items, $total, $perPage, $page
);
You can create a Paginator like this:
$page = request()->get('page'); // By default LengthAwarePaginator does this automatically.
$collection = collect(...array...);
$total = $collection->count();
$perPage = 10;
$paginatedCollection = new \Illuminate\Pagination\LengthAwarePaginator(
$collection,
$total,
$perPage,
$page
);
According to the source code for LengthAwarePaginator (constructor)
public function __construct($items, $total, $perPage, $currentPage = null, array $options = [])
{
foreach ($options as $key => $value) {
$this->{$key} = $value;
}
$this->total = $total;
$this->perPage = $perPage;
$this->lastPage = (int) ceil($total / $perPage);
$this->path = $this->path != '/' ? rtrim($this->path, '/') : $this->path;
$this->currentPage = $this->setCurrentPage($currentPage, $this->pageName);
$this->items = $items instanceof Collection ? $items : Collection::make($items);
}
See more about LengthAwarePaginator
To display links in the view:
$paginatedCollection->links();
Hope this helps!

Pagination with array not working in laravel 5.1

I have to set pagination in array result.
Here is my code.
My Controller code
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\LengthAwarePaginator;
public function getCVList(){
.
.
.
$jobseeker1 = array_merge($jobseekers, $apps_array);
// in $jobseeker1 there are 6 result.
$jobseeker = $this->paginate($jobseeker1, 3);
return view('frontend.CVList', compact('jobseeker'));
}
public function paginate($items, $perPage, $pageStart = 1) {
$offSet = ($pageStart * $perPage) - $perPage;
// Get only the items you need using array_slice
$itemsForCurrentPage = array_slice($items, $offSet, $perPage, true);
return new LengthAwarePaginator($itemsForCurrentPage, count($items), $perPage, Paginator::resolveCurrentPage(), array('path' => Paginator::resolveCurrentPath()));
}
In blade temoplate i used rander() method and thare are also display pagination. But in all page display same record.
Thanks....
This is because you are not reading the page number clicked in the paginator, you are setting "3" always as the page to display. Try this:
//include the request
use Illuminate\Http\Request;
Now, read the current page:
public function getCVList(Request $request){
$perPage = 3;
// read the page number. When page number is not presented, then you
// set it as 0
$page = $request->get('page', 0);
$page = ($page == 0)? ($page * $perPage) : ($page * $perPage) - $perPage;
// now, calling the paginator do magic dynamically
$jobseeker = $this->paginate($jobseeker1, $perPage, $page);

How can I paginate an array of objects in Laravel?

I'm building an application using Laravel 4.2. I have a model for units and another for users and pivot table user_units. Every user in this application can select a unit and add it to his favorite list then he can publish this unit with his information as an ad.
I want to select all units published by all users
The user_units (pivot) table has the following columns:
id
user_id
unit_id
publish
adtype
addinfo
created_at
updated_at
With relations methods on models
public function users() {
return $this->belongsToMany('User', 'user_units')
->withPivot('id','publish', 'adtype', 'addinfo');
}
public function units() {
return $this->belongsToMany('Unit', 'user_units')
->withPivot('id','publish', 'adtype', 'addinfo');
}
My query to select all published units by all users
// Get all published units by users for sale.
$users = User::all();
$publishedSaleUnits = [];
foreach($users as $user){
$userUnits = $user->units()->orderBy('adtype', 'desc')->get();
if(count($userUnits)){
foreach($userUnits as $unit){
if($unit->pivot->publish == 1 && $unit->unit_purpose_id == 1){
if( $unit->pivot->adtype ){
//push all featured ads onto the beginning of array
array_unshift($publishedSaleUnits, $unit);
}else{
//push all normal ads onto the end of array
array_push($publishedSaleUnits, $unit);
}
}
}
}
}
Now I got the result but I can't use pagination with results because it's an array of objects.
So is there any better solution to get all published units by user with pagination?
according to this article
https://www.itsolutionstuff.com/post/how-to-create-pagination-from-array-in-laravelexample.html
you can paginate your array by creating a custom method and using LengthAwarePaginator
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
class PaginationController extends Controller
{
public function index()
{
$myArray = [
['id'=>1, 'title'=>'Laravel CRUD'],
['id'=>2, 'title'=>'Laravel Ajax CRUD'],
['id'=>3, 'title'=>'Laravel CORS Middleware'],
];
$data = $this->paginate($myArray);
return view('paginate', compact('data'));
}
public function paginate($items, $perPage = 5, $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);
}
}
Your approach to query the data is extremely inefficient. Fetch your data in one query. Nested traversing is not only hard to read but also a performance killer.
To the pagination problem:
Laravel provides a Pagignator Factory. With it you will be able to build your own Paginator with your own data.
It's as easy as
$units = Paginator::make($unit, count($unit), 10);
if you're using the Facade. Otherwise Illuminate\Pagination\Factory is the class you are looking for.
You can try my code with your own array,
$page = isset($request->page) ? $request->page : 1; // Get the page=1 from the url
$perPage = $pagination_num; // Number of items per page
$offset = ($page * $perPage) - $perPage;
$entries = new LengthAwarePaginator(
array_slice($contact_list, $offset, $perPage, true),
count($contact_list), // Total items
$perPage, // Items per page
$page, // Current page
['path' => $request->url(), 'query' => $request->query()] // We
need this so we can keep all old query parameters from the url
);
I got a better solution to paginate array result and I found the answer here
Paginator::make function we need to pass only the required values instead of all values. Because paginator::make function simply displays the data send to it. To send the correct offset paginated data to the paginator::make, the following method should be followed
$perPage = 5;
$page = Input::get('page', 1);
if ($page > count($publishedSaleUnits) or $page < 1) { $page = 1; }
$offset = ($page * $perPage) - $perPage;
$perPageUnits = array_slice($publishedSaleUnits,$offset,$perPage);
$pagination = Paginator::make($perPageUnits, count($publishedSaleUnits), $perPage);
this code work for me on laravel 8
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
public function paginate($items, $perPage = 5, $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);
}
according to this refrence https://www.itsolutionstuff.com/post/how-to-create-pagination-from-array-in-laravelexample.html

pagination doesn't work in codeigniter

I have successfully created pagination on some of the pages on the application on which I am working with, but I can't make it on this one:
I have 7 records in the database, and when
page is displayed all 7 records are displayed instead of 5, as I would like to be.
Sure enough, links for the paging are not displayed.
Here is my controller code:
public function displayAllFaqCategories()
{
//initializing & configuring paging
$currentUser = $this->isLoggedIn();
$this->load->model('faqCategoriesModel');
$this->db->order_by('sorder');
$limit = 5;
$offset = 3;
$offset = $this->uri->segment(3);
$this->db->limit(5, $offset);
$data['faq_categories'] = $this->faqCategoriesModel->selectCategoriesAndParents();
$totalresults = $this->db->get('faq_categories')->num_rows();
//initializing & configuring paging
$this->load->library('pagination');
$config['base_url'] = site_url('/backOfficeUsers/faqcategories');
$config['total_rows'] = $totalresults;
$config['per_page'] = 5;
$config['uri_segment'] = 3;
$this->pagination->initialize($config);
$errorMessage = '';
$data['main_content'] = 'faq/faqcategories';
$data['title'] = 'FAQ Categories';
$this->load->vars($data,$errorMessage);
$this->load->vars($currentUser);
$this->load->view('backOffice/template');
} // end of function displayAllFaqCategories
And here is my model function code:
public function selectCategoriesAndParents($selectWhat = array())
{
$data = array();
$query = $this->db->query("SELECT fq . * , COALESCE( fqp.$this->parent_name, '0' ) AS parentname
FROM $this->table_name AS fq
LEFT OUTER JOIN $this->table_name AS fqp ON fqp.catid = fq.parentid");
if($query->num_rows() > 0)
{
foreach($query->result_array() as $row)
{
$data[] = $row;
}
}
$query->free_result();
return $data;
} // end of function selectCategoriesAndParents
In the view, bellow of the table with the records I have the following code:
<?php echo $this->pagination->create_links();?>
Any help will be deeply appreciated.
Regards,Zoran
You've mixed two different things together I think. You're partially using the ActiveRecord class of CI, but then running the query yourself.
The simplest change would be:
// get all the rows
$data['faq_categories'] = $this->faqCategoriesModel->selectCategoriesAndParents();
// figure out the count of all of them
$totalresults = count($data['faq_categories']);
// only take some of the rows of the array, instead of keeping all of them and then showing all 7 of your records
$data['faq_categories'] = array_splice($data['faq_categories'], $offset, $limit);
Hopefully that should fix it!
To further explain what the original problem is, I think when you run this:
$totalresults = $this->db->get('faq_categories')->num_rows();
It takes the previous line $this->db->limit(5, $offset); into account, so it only returns 5 rows. Then, when you tell the pagination library that you only want to show 5 per page, the library thinks that it is actually showing all the results, so there is no need for pagination links!
Edit like this
$offset = $this->uri->segment(3) ? $this->uri->segment(3) : 0;

Resources