This is a package that filter queries with user's custom methods.
- PHP >= 8.0
- Laravel >= 9.0
composer require bakhadyrovf/easy-filter
Laravel uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider.
php artisan vendor:publish --tag=easy-filter-config
The namespace for filters by default App\Filters
and each filter class before creating expects that you already have Eloquent Model with the namespace standards as follows:
Filter | Model |
---|---|
App\Filters\UserFilter |
App\Models\User |
App\Filters\Dashboard\ArticleFilter |
App\Models\Dashboard\Article |
App\EloquentFilters\TagFilter |
App\Models\Tag |
First of all you must create filter class:
php artisan make:filter ArticleFilter
This command creates ArticleFilter class in your project's app/Filters folder.
Also this command adds trait Filterable to your Eloquent Model.
You can change base folder's name in your config file (Namespace will be changed as well):
<?php
return [
/**
* Base folder's name in app directory.
* Default: Filters
*/
'base-folder' => 'Filters'
];
Also, you can generate a filter class with subfolder:
php artisan make:filter Dashboard/ArticleFilter
Filter class will be located in app/Filters/Dashboard folder.
The newly created class will looks like this:
<?php
namespace App\Filters\ArticleFilter;
use Bakhadyrovf\EasyFilter\QueryFilter;
class ArticleFilter extends QueryFilter
{
}
If the namespace of your Model or Filter does not match the above, you can use --model
option:
For example - we have model with namespace App\Models\Article
, we want to create a filter class with namespace App\Filters\Dashboard\ArticleFilter
:
php artisan make:filter Dashboard/ArticleFilter --model=App\\Models\\Article
In order for a filter that does not match the namespace with the model, you must add method on your App\Models\Article
class:
<?php
namespace App\Models\Admin;
use Bakhadyrovf\EasyFilter\Traits\Filterable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Filters\Dashboard\ArticleFilter;
class Discount extends Model
{
use HasFactory, Filterable;
public function provideFilter()
{
return ArticleFilter::class;
}
}
This method will point to a specific filter class.
Now, you can write your methods inside filter class. Let's add first method and try to filter our query. In app/Filters/ArticleFilter:
class ArticleFilter extends QueryFilter
{
public function title(Builder $builder, $value)
{
return $builder->where('title', 'LIKE', $value . '%');
}
}
Method Arguments
- $builder - Illuminate\Database\Eloquent\Builder
- $value - Value taken from request
And you can try to filter query using filter()
method on your Eloquent Model.
This method is basic Eloquent Scope so you can use it as usually.
In app\Http\Controllers\ArticleController:
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
public function index(Request $request)
{
$articles = Article::filter()
->orderByDesc('id')
->get();
return $articles;
}
}
All parameters that are responsible for filtering must be in query:
example.com/articles?title=some-title
If your parameter is in snake case, you don't need to create a method with the same case, because it doesn't match php standards. The package itself converts the parameter to camel case.
For example if your parameter is first_name:
example.com/articles?first_name=some-value
Method will be looks like this:
Class ArticleFilter extends QueryFilter
{
public function firstName(Builder $builder, $value)
{
return $builder->where('first_name', 'LIKE', $value . '%');
}
}
Multiple values
If your parameter can take multiple values, you can use brackets:
example.com/articles?category_ids=[1,2,3,4,5]
As usual, these values will be in the method's second argument
Class ArticleFilter extends QueryFilter
{
public function categoryIds(Builder $builder, $values)
{
return $builder->whereHas('categories', function ($query) use ($values) {
return $query->whereIn('id', $values);
});
}
}
Ignoring parameters
For example if you want to ignore post_ids parameter from filtering:
https://example.com/users?name=Firuzbek&post_ids=[1,10,25]
You can provide exceptions array of method names or query parameters as an argument to filter()
method:
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index(Request $request)
{
$users = User::active()
->filter(['postIds']) // Or post_ids
->orderByDesc('created_at')
->get();
return $users;
}
}
Multiple filters
If you have multiple filter classes for one model, you can provide specific filter class as a second argument.
This filter class will be used even if you have a provideFilter()
method on the model:
use App\Models\Post;
use App\Filters\Dashboard\PostFilter;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index(Request $request)
{
$posts = Post::active()
->filter(['sort_by'], PostFilter::class)
->orderByDesc('created_at')
->get();
return $posts;
}
}