Laravel 5.1 pagination groupby links rendering - php

I am on Laravel Framework version 5.1.45 (LTS).
One club can have many events. I am trying to list all the events, group them by year and show one page per year.
According to my Laravel version documentation "Currently, pagination operations that use a groupBy statement cannot be executed efficiently by Laravel. If you need to use a groupBy with a paginated result set, it is recommended that you query the database and create a paginator manually."
Here is my attempt to create the paginator manually and it seems to do the job:
public function index()
{
$page = Paginator::resolveCurrentPage() - 1;
$perPage = 1;
$events = new Paginator(Event::orderBy('date', 'desc')->groupBy(DB::raw('YEAR(date)'))->skip(($page - 1) * $perPage)->take($perPage + 1)->get(), $perPage, $page);
$events->setPath(['events/events']);
return view('events.index', ['events' => $events]);
}
And here is how I try to display the links at the bottom of the page.
{!! $events->render() !!}
If I remove the render bit, the page is displayed, albeit with no links. I can even go to the next page (year 2016) adding manually ?page=2 at the end of the url in my browser.
But if I leave the render bit in the index page, I get ErrorException in AbstractPaginator.php line 130: Array to string conversion.
What am I doing wrong?

Hope this snippet can help
public function index(Request $request)
{
$posts = Post::all()
->paginate($request->get('per_page', 25));
$grouped_by_date = $posts->mapToGroups(function ($post) {
return [$post->published_date => $post];
});
$posts_by_date = $posts->setCollection($grouped_by_date);
return view('posts.index', compact('posts_by_date'));
}
Basically redefine the collection with the grouped collection.

Related

Laravel - Paginate function doesn't working on query building using IF

I am using paginate() on my Controller to pass data to the View. This is my index function using the paginate()
$userData = User::with('jobUnit')
->select('nip','name','address','phone','email','unit_id')
->paginate(10);
return view('users.index', [
'users' => $userData
]);
This is the result:
In the other function, I needed to add some IF conditions on the queries that is look like this:
$keyword = $request->keyword;
$searchedData = User::with('jobUnit')->select('nip','name','address','phone','email','unit_id');
if ($request->searchFilter == 'nip') {
$searchedData->where('nip','like','%'.$keyword.'%');
}
$searchedData->paginate(10);
The results is different, which is a problem for me because I am using the pagination links in the View. Here is the results:
Does the pagination() not working? Because I tried using the get() as well which should returns "Collection", but it was still returning the "Builder" results.
you need another variable to store the return data
$searchDataPaginated = $searchedData->paginate(10);
or using the current one if you want
$searchedData = $searchedData->paginate(10);

Laravel Pagination with Get request

I've followed the instructions on the Laravel documentation for pagination with appends([]) however I'm having a little trouble with the persistence of these parameters.
Say for example, I pass home?category=Cars&make=Tesla to my view. What is the best way to paginate with them Get requests?
Right now I've passed the category as a parameter to the view as (where category is the model i've grabbed findOrFail with the request('category');)
$category_name = $category_model->name;
And then in my view it's like so:
{{ $vehicles->appends(['category' => $category_name])->links() }}
But when I go between pages in the pagination, this $category_name value doesn't seem to persist. Whats the recommended way to achieve what I want?
Thanks.
You can append the query string in your controller when you paginate the result. I'm not sure if that was your only question or even regarding applying the query string as a condition. So here is a sample showing you how to do both. This should give you an idea of how to do it. I just assumed the column names in this example.
$category = request('category');
$make = request('make');
$vehicles = Vehicle::when($category, function ($query) use ($category) {
return $query->where('category', $category);
})
->when($make, function ($query) use ($make) {
return $query->where('make', $make);
})
->paginate(10);
$vehicles->appends(request()->query());
return view('someview', compact('vehicles'));

Laravel Eloquent pagination control page number with route

Articles::paginate(10)
This code will return the 1st 10 articles, what if I want to return the next 10 articles with route? For example the url mypage.com/articles/2 will return the 2nd 10 articles from database.
This is so far what I have:
Route:
Route::get('articles/{page_number}', 'Controller#getArticles')
Controller:
public function getArticles($page_num)
{
$perPage = 10;
Articles::getPaginator()->setCurrentPage($page_num);
$articles = Articles::paginate($perPage);
return $articles;
}
Can I have something like Articles::pageNumber($page_number)->paginate($perPage);?
Laravel paginator automatically checks for the the value of page in query string and uses it to paginate the results. The result also automatically generates the next and previous links to help you add them directly. You don't need to change anything to make it work.
In your case you can use $articles->links() in your view to generate the pagination navigation buttons. But if you want to manually set the page then you can do this.
$articles = Articles::paginate(5, ['*'], 'page', $pageNumber);
The default paginate method takes the following parameters.
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null);
The default convention is
mypage.com/articles?page=2
mypage.com/articles?page=3
Also if you use $articles->links() to generate the navigation button, you can also customize the css.
Check out https://laravel.com/docs/5.4/pagination for more info
$results= DB::table('subscribers')->select('id', 'name', 'email')->paginate(20);
$results->count();
$results->currentPage();
$results->firstItem();
$results->hasMorePages();
$results->lastItem();
$results->lastPage(); (Not available when using simplePaginate)
$results->nextPageUrl();
$results->perPage();
$results->previousPageUrl();
$results->total(); (Not available when using simplePaginate)
$results->url($page);

Laravel 5.2 - filtering on a custom attribute and then paginating

So I know how to paginate using paginate() and I know how to filter based on an Accessor (a where() on the collection). However, paginate takes in a query builder and where() on a collection returns a collection.
So if I want to get a bunch of items / filter by a custom attribute and then paginate the result set....how do i do that??
Accessor:
public function getRequiredToReportAttribute()
{
// return boolean based off of complicated business logic
}
index method:
public function index()
{
//what im doing (redacted)
$employers = (new App\Employers')->paginate($this->perPage);
// what I would like to be doing
$employers = (new App\Employers)->where('required_to_report', '=', true)->paginate($this->perPage);
return $this->sendResponse($employers);
}
In the case that you want to work with accesors, you could by iterating the collection after you get your query, something like this:
$result = Model::get()->filter(function($item) {
return $item->require_to_report === true;
});
Here you have all records of your model and then you could create a manual paginator:
$paginator = new Illuminate\Pagination\Paginator($result, 10);
you have with this approach a weakness when you have too many records, the performance could be affected.
Based off of Jose Rojas answer and this post I built a LengthAwarePaginator for a collection filtering on an attribute accessor. Here's an example of how to do it:
$collection = Model::all();
//Filter your collection
$filteredItems = $collection->filter(function($col) {
return $col->require_to_report === true;
});
// Setup necessary information for LengthAwarePaginator
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$pageLimit = 20;
// slice the current page items
$currentItems = $filteredItems->slice(pageLimit * ($currentPage - 1), pageLimit)->values();
// you may not need the $path here but might be helpful..
$path = "/api/v1/employers";
// Build the new paginator
$paginator = new LengthAwarePaginator($currentItems, count($filteredItems), $pageLimit, $currentPage, ['path' => $path]);
return $paginator;

Laravel Custom Pagination

Having problems getting my pagination to work in Laravel 5.2 I use a foreach to generate a list of objects where each object has a certain ranking. (competition)
The first query I used was this one:
$goedeDoelen = GoedDoel::orderBy('punten', 'desc')->simplePaginate(5);
This worked pretty ok, only problem was that my ranking would reset everything I would go to a different page.
Example: Page 1 has objects from rank 1 - 5, page 2 should have ranks 6-10. By using the first Paginate method, the second page would have objects starting from 1 again.
I have tried to work around this by adding the ranking as an extra attribute to my Eloquent collections.
$ranking = GoedDoel::orderBy('punten', 'desc')->get();
foreach($ranking as $key => $item) {
$item->ranking = $key+1;
}
After that I tried to use ->simplePaginate() on my updated collection. This gave an error.
I have created a custom Paginator.
$goedeDoelen = new Paginator($ranking, 5);
This isn't working as intended. When I go to my second page, the URL messes up and goes to another view.
How can I make sure the Paginator knows what my current URL is to which it has to apply the ?page=2
You need to use the paginate() method.
$goedeDoelen = GoedDoel::orderBy('punten', 'desc')->paginate(5);
{!! $goedeDoelen->links() !!}
The following Code illustrates manual pagination in Laravel
Sample Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator as Paginator;
use App\Models\UserRechargeDetails;
class PaginateController extends Controller
{
//
public function index(Request $request)
{
$user_1 = new UserRechargeDetails;
// Get records from Database
$items = $user_1->all();
// Store records in an array
$records = [];
$i = 0;
foreach($items as $item)
{
$records[$i][0] = $item->user_name;
$records[$i][1] = $item->rech_mobile;
$i++;
}
// Current page for pagination
$page = $request->page;
// Manually slice array of product to display on page
$perPage = 2;
$offset = ($page-1) * $perPage;
$data = array_slice($records, $offset, $perPage);
// Your pagination
$final_data = new Paginator($data, count($records), $perPage, $page, ['path' => $request->url(),'query' => $request->query(),]);
/*
For Display links, you may add it in view page
{{ $data->links('pagination::bootstrap-4') }}
*/
return view('admin.pagination_new', ['data' => $final_data, 'j' => 1]);
}
}

Categories