Laravel append overall total value on pagination result - laravel

I have a Laravel query using pagination.
I want to be able to return the result based on the pagination but also get the overall total of the query and append this to the return. So for example the pagination is set to 5 but the overall total might be 20.
$query = Model::paginate(5);
$queryTotal = $query->total();
$query->append($queryTotal);
return $query;

The Laravel Paginator does this already.
You can see that when serializing results to JSON there is a total key which represents all rows matching that query.
You can also see there is a total method available from the paginator:
$results->total()
Along side other methods that can be found in the Pagination Docs

$query = Model::paginate(5);
return $query;
You can access overall total using
{{ $query->total() }}
For more Info read Paginator instance

The paginate function returns a LengthAwarePaginator object. It simply not possible to add another field to this object.
Your best option is to manually create a new collection in which you merge the LengthAwarePaginator with your newly added data.
An example would be:
$query = Model::paginate(5);
$addition = collect(['totalResult' => $query->total()]);
$queryData = $addition->merge($query);
return $queryData;
Naturally, if you just return the LengthAwarePaginator object, you can simply call the total() function, if you use it in your blade files for example.
Hope this helps!

Related

Laravel 7 API Resource showing only data that contains relationship

This my code stored in my API Controller:
return ApartmentResource::collection(Apartment::with(['sponsors'])->paginate(5));
It shows all Apartments, someone have the sponsor array empty, someone not.
How i can show only the Apartments that actually have sponsors?
You can use the has() method
https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence
return ApartmentResource::collection(Apartment::has('sponsors')->with(['sponsors'])->paginate(5));
with() simply eager loads the sponsors: https://laravel.com/docs/9.x/eloquent-relationships#eager-loading
use array_filter()
example:
$result = array_filter($array);
array_filter() remove empty array elements from array.

Laravel, how to convert a collection object into a builder object

I need to use paginate and simplepaginate on a collection, so i'm trying to convert the collection into a builder object.
To do so I am thinking of creating a function that gets the id of every item in the collection and then builds a query with it, but that seemed to me like a lot of resources waisted,
Is there a simpler way ?
A better way to do this is to build paginator object manually using the existing collection.
From the docs:
Sometimes you may wish to create a pagination instance manually, passing it an array of items. You may do so by creating either an Illuminate\Pagination\Paginator or Illuminate\Pagination\LengthAwarePaginator instance, depending on your needs.
The Paginator class does not need to know the total number of items in the result set; however, because of this, the class does not have methods for retrieving the index of the last page. The LengthAwarePaginator accepts almost the same arguments as the Paginator; however, it does require a count of the total number of items in the result set.
In other words, the Paginator corresponds to the simplePaginate method on the query builder and Eloquent, while the LengthAwarePaginator corresponds to the paginate method.
Building on what Alexey said, as alternative, you can build a Paginator from a collection manually. This is a simpler way without the waste of an additional query. e.g.
// Collection $collection
$perPage = 10;
$currentPage = Illuminate\Pagination\Paginator::resolveCurrentPage() ?? 1;
$itemsOnPage = $collection->skip(10 * ($currentPage-1))->take($perPage);
$paginatorPath = Illuminate\Pagination\Paginator::resolveCurrentPath();
$paginator = new \Illuminate\Pagination\LengthAwarePaginator(
$itemsOnPage,
$collection->count(),
$perPage,
$currentPage,
['path' => $paginatorPath]
);
Then in your view,
{!! $paginator->render() !!}

How to handle new incoming entries while paging through posts?

Let's assume I have a pagination like this
return App\Post::paginate(1);
After loading this someone creates a new entry in the database for posts. How can i ensure that the "second page" of my pagination does not return the first one again?
Will I always need to send a timestamp with every request to make an additional query before pagination is used?
like
App\Post::where('created_at', '<', $request->input('max_created_at'))->paginate(1);
You can use orderBy. You could do something like that:
// Get the last post (most recent)
return App\Post::orderBy('created_at', 'DESC')->paginate(1);
Or:
// Same as above
return App\Post::orderBy('created_at', 'DESC')->first();
orderBy means all you result are sorted in your query. Hope it will help.
You don't need to pass any timestamp value to verify pagination.
In the controller, in view file you need to pass result of this query.
$result = App\Post::orderBy('created_at', 'desc')->paginate(1);
return view('pagination',compact('result'));
In view file you need below line for pagination work automatically as per Laravel syntax.
{{ $result->links() }}
Visit https://laravel.com/docs/5.2/pagination/ how laravel pagination work.

Laravel 5.1 eloquent query orderby external data and paginated

I'm trying to get data from an Eloquent query (that works), then order the data, then paginate the data.
I had the code ordering by date, then paginating, but now I want to order by facebook API obtained data (I get the data correctly).
The thing is I don't know what I should do first (paginate or ordering):
If I paginate first, I don't know how to order the data since the object is LengthAwarePaginator and doesn't have any orderBy method.
If I order first, I get a collection object and can't use ->paginate($perPage) to do the pagination.
This is the code:
$posts = Post::with('User')->
where('created_at', '<', new \DateTime)->
paginate($perPage);
$counter = 0;
foreach ($posts as $post) {
$url = 'http://myweb.com/' . $post['id'];
$fb_stuff = json_decode(file_get_contents('https://api.facebook.com/method/links.getStats?urls=' . $url . '&format=json'), true);
$posts[$counter]['share_count'] = $fb_stuff[0]['share_count'];
$counter++;
}
If you need to sort by some value that is not stored in the database then the only option is to fetch all records from the database, fetch the sorting data from external source (Facebook API), sort it by user defined function (see http://php.net/manual/en/function.usort.php) and then paginate.
Once you have your data sorted you can easily get the paginated version by creating a Paginator object:
$paginator = new \Illuminate\Pagination\Paginator($posts, $perPage, $currentPage);
Anyway, this solution will be quite heavy as you'll need to fetch data from Facebook API every time you want a sorted list of posts. I doubt you need real time data so I suggest to store share_count in your posts table and refresh it on regular basis, e.g. by running a scheduled laravel command.

Laravel Paginator getTotal returns null - Need total record count for all pages

I have implemented simple pagination using laravel. It works fine. However, I want to add total number of records and trying to use the method getTotal() but it returns null value.
$records = DB::table('tablename')
->where(condition)
....
....
->simplePaginate(10);
In the view, adding links works fine.
{{$records->links();}}
When I use,
{{$records->getTotal();}}
it returns null.
If I use,
{{$records->count();}}
it returns the count of records for a given page.
Any insights please?
That's how simplePaginate works. From the docs:
If you are only showing "Next" and "Previous" links in your pagination view, you have the option of using the simplePaginate method to perform a more efficient query. This is useful for larger datasets when you do not require the display of exact page numbers on your view.
The simple method is simple because it doesn't need to do the extra, inefficient-on-large-tables count query to obtain the total.
There is method total() in that pagination object. Just call that object. You will get total count.
ex: $records->total();
I had the same problem, what I did was
$records = DB::table('tablename')
->where(condition)
....
....
->paginate(1); //set as 1
$total = $records->getTotal(); //get total
Then returning it like this(I am using ajax that is why I return it as array):
return Response::JSON(array(
'pagination' => (string) $records->links('pagination::simple'),
'total_records' => $total
));

Resources