Medala's avatar
Level 12

How to paginate while using custom Filter class?

Hi, I have a ProductFilters class for a dynamic filter function as shown here: https://laracasts.com/series/eloquent-techniques/episodes/4.

Pagination and the filters are working if applied separately.

This does not append {{ $products->appends(request()->query())->links() }} Neither this {{ $products->appends(Request::except('page'))->links() }}

What should I do?

0 likes
6 replies
jlrdw's avatar

Can you put more detail and code you tried, that way folks will be better able to help.

Medala's avatar
Level 12

HERE IS THE QUERYFILTERS INHERITED BY THE PRODUCTFILTERS @jlrdw

<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;



abstract class QueryFilter
{
    protected $request;
    protected $builder;

    public function __construct(Request $request)
    {
        $this->request = $request;    
    }

    public function apply(Builder $builder)
    {
        $this->builder = $builder;
        foreach($this->filters() as $name => $value){
            if(method_exists($this, $name)){
                call_user_func_array([$this, $name], array_filter([$value]));
            }        
        }
        return $this->builder;
    }

    public function filters()
    {
        return $this->request->all();
    }
}

THE PRODUCT FILTER

<?php

namespace App;

class ProductFilters extends QueryFilter
{
    // THIS IS THE ONLY FILTER FOR NOW, IT WILL GROW TO 50 MAYBE.
    public function price($order = 'desc')
    {
        return $this->builder->orderBy('price', $order);
    }

THE CONTROLLER

    public function index(ProductFilters $filters)
    {
       
       $products = Product::filter($filters)->paginate(10);
       return view('products', compact('products'));

    }

THE ROUTE

Route::resource('products', 'ProductController');

THE BLADE

    @foreach(array_chunk($products->getCollection()->all(), 4) as $row)
    <div class="row">
        @foreach($row as $product)
        <div class="mediapic col-md-3" id="mediapic">
            <a href="products/{{$product->id}}">
                <img class="card-img-top rounded mediapic2" src="https://picsum.photos/512/512" alt="Card image cap"
                    width="250" height="250">
                <a href="#" class="btn btn-primary btn-sm">Check it out</a>
            </a>
            <div class="bottom-left">

                {{$product->title}}
                <h6><strong>{{$product->price}}</strong></h6>
            </div>

        </div>
        @endforeach
    </div>
        @endforeach
    </div>

    {{ $products->appends(request()->query())->links() }}



Medala's avatar
Level 12

And the Product class:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Product extends Model
{
    protected $guarded=[];
    use Searchable;

    public function productImage()
    {
        return $this->hasMany(ProductImage::class);
    }

    public function scopeFilter($query, QueryFilter $filters)
    {
        return $filters->apply($query);
    }

Medala's avatar
Level 12

Thanks @jlrdw

I can use the pagination and the query filter separately. Going to page 2 does not maintain the query for "price" , it just goes to the normal page2.

I have a page with the "price" filter applied,

http://localhost:8000/products?price

then i go to page 2, the url only shows

http://localhost:8000/products?page=2
Medala's avatar
Level 12

Thanks @jlrdw I already have an object to return and paginate with the filter, I created a new query in ProductFilters and this one works. I wonder why it doesn't work for the full range price sort.

class ProductFilters extends QueryFilter
{

    public function price($order = 'desc')
    {
        return $this->builder->orderBy('price', $order);
    }

    public function priceBelow($price)
    {
        return $this->builder->where('price', '<=', $price);   
    }

The second one works http://localhost:8000/products?priceBelow=300&page=3

Please or to participate in this conversation.