abbasudo/laravel-purity
Laravel Purity adds elegant filtering and sorting to Eloquent queries. Just call filter() on a model query, then let clients apply complex conditions via URL query parameters (e.g., filters[title][$contains]=...). Great for clean, flexible APIs.
composer require abbasudo/laravel-purity
php artisan vendor:publish --tag=purity
use Abbasudo\Purity\Traits\Filterable;
use Abbasudo\Purity\Traits\Sortable;
class Post extends Model
{
use Filterable, Sortable;
}
return Post::filter()->sort()->get();
// Filter example
const query = qs.stringify({
filters: {
title: { $contains: 'Purity' }
}
});
// Sort example
const sortQuery = qs.stringify({
sort: ['title:asc', 'created_at:desc']
});
Build a searchable API endpoint where users can filter and sort posts via URL parameters. Example:
GET /api/posts?filters[title][$contains]=Laravel&sort[0]=created_at:desc
Basic Filtering:
// Controller
$posts = Post::filter()->get();
// URL: /api/posts?filters[title][$eq]=Hello
$eq, $contains, $gt, etc. from query string.Sorting:
// Controller
$posts = Post::sort()->get();
// URL: /api/posts?sort[0]=title:desc&sort[1]=created_at:asc
:asc/:desc suffixes.Livewire Integration:
// Component
#[Url]
public $filters = ['title' => []];
public function render()
{
return Post::filter($this->filters)->get();
}
$filters array:
<input wire:model.live="filters.title.$eq" placeholder="Exact title">
Relation Handling:
// Model
public function tags(): HasMany { return $this->hasMany(Tag::class); }
// Related Model (Tag)
protected $filterFields = ['name']; // Restrict allowed fields
// URL: /api/posts?filters[tags.name][$contains]=Tech
Purity::getFilters()/Purity::getSorts() to inspect applied filters/sorts in resource classes.PurityServiceProvider to add custom validation rules for filters.get() with large datasets.Purity in tests by overriding filter()/sort() methods.Field Restrictions:
$filterFields in v3+ restricts (not renames) fields. Use renameFields for aliases:
protected $renameFields = ['published_at' => 'date'];
$filterFields in related models breaks relation filtering.Silent Exceptions:
silent: true in config. Set to false for debugging:
'silent' => env('APP_DEBUG'), // Dynamic toggle
Nested Relations:
posts.tags.user.name will fail. Use flat dot notation (tags.name).Case Sensitivity:
$eq is case-insensitive; use $eqc for case-sensitive matches.URL Encoding:
title:desc → title%3Adesc). Use qs library:
qs.stringify({ sort: ['title:desc'] }, { encodeValuesOnly: true });
$filters = Purity::getFilters(request());
$sorts = Purity::getSorts(request());
\Log::debug('Raw filters:', request()->query('filters'));
tinker:
php artisan tinker
>>> Post::filter()->toSql(); // See generated SQL
Custom Filters:
PurityServiceProvider:
Purity::extend('custom', function ($query, $value) {
return $query->where('column', 'LIKE', "%{$value}%");
});
?filters[column][custom]=valueDynamic Field Whitelisting:
getFilterFields() in model:
public function getFilterFields(): array
{
return ['title', 'published_at'];
}
Silent Mode:
Purity::setSilent(false);
Livewire Debouncing:
<input wire:model.debounce.500ms.live="filters.title.$contains">
How can I help you explore Laravel packages today?