Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filtering a paginated eloquent collection

I am trying to filter a paginated eloquent collection, but whenever I use any of the collection methods, I lose the pagination.

$models = User::orderBy('first_name','asc')->paginate(20);

$models = $models->each(function($model) use ($filters) {
    if(!is_null($filters['type'])) {
        if($model->type == $filters['type'])
            return $model;
    }

    if(!is_null($filters['state_id'])) {
        if($model->profile->state_id == $filters['state_id'])
            return $model;
    }

    if(!is_null($filters['city_id'])) {
        if($model->profile->city_id == $filters['city_id'])
            return $model;
    }
});

return $models;

I am working with Laravel 4.2, is there any way to persist the pagination?

like image 768
MrFoh Avatar asked Apr 24 '15 09:04

MrFoh


People also ask

Can you Paginate a collection in Laravel?

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.

What is pagination method?

Simple Pagination The paginate method counts the total number of records matched by the query before retrieving the records from the database. This is done so that the paginator knows how many pages of records there are in total.

What does Paginate do in Laravel?

The paginate method provided by Laravel automatically takes care of setting the proper limit and offset based on the current page being viewed by the user. By default, the current page is detected by the value of the ? page query string argument on the HTTP request.


2 Answers

An answer to the titular question, which is possible in Laravel 5.2+:

How to filter the underlying collection of a Paginator without losing the Paginator object?

You can eject, modify and inject the collection as follows:

$someFilter = 5;
$collection = $paginator->getCollection();
$filteredCollection = $collection->filter(function($model) use ($someFilter) {
  return $model->id == $someFilter;
});
$paginator->setCollection($filteredCollection);

The Paginator is built on an underlying collection, but indeed when you use any of the inherited Collection methods they return the underlying collection and not the full Paginator object: collection methods return collections for chaining together collection calls.

like image 60
Robin De Schepper Avatar answered Oct 09 '22 11:10

Robin De Schepper


Expanding on mininoz's answer with your specific case:

//Start with creating your object, which will be used to query the database

$queryUser = User::query();

//Add sorting

$queryUser->orderBy('first_name','asc');

//Add Conditions

if(!is_null($filters['type'])) {
    $queryUser->where('type','=',$filters['type']);
}

if(!is_null($filters['state_id'])) {
    $queryUser->whereHas('profile',function($q) use ($filters){
        return $q->where('state_id','=',$filters['state_id']);
    });
}

if(!is_null($filters['city_id'])) {
    $queryUser->whereHas('profile',function($q) use ($filters){
        return $q->where('city_id','=',$filters['city_id']);
    });
}

//Fetch list of results

$result = $queryUser->paginate(20);

By applying the proper conditions to your SQL query, you are limiting the amount of information that comes back to your PHP script, and hence speeding up the process.

Source: http://laravel.com/docs/4.2/eloquent#querying-relations

like image 28
Mysteryos Avatar answered Oct 09 '22 11:10

Mysteryos