composer require jedrzej/pimpable
use PimpableTrait; to your Eloquent model (e.g., Post.php).
class Post extends Model
{
use PimpableTrait;
}
pimp():
public function index()
{
return Post::pimp()->get(); // Handles filtering, sorting, and eager loading via request params
}
Scenario: Fetch posts with:
42is_active (desc) then created_at (desc)user relationRequest:
GET /api/posts?thread_id=42&text=%awesome%&sort[]=is_active,desc&sort[]=created_at,desc&with=user
Request Handling:
filter, sort, with) into query constraints.filter[field]=value (e.g., filter[status]=published)filter[field][op]=value (e.g., filter[created_at][ge]=2023-01-01)sort[]=field,order (e.g., sort[]=created_at,desc)with[]=relation1,relation2 (e.g., with[]=user,comments)Chaining Methods:
Combine pimp() with other query builders:
Post::where('draft', false)->pimp()->get();
Customizing Behavior:
pimpable() method in your model:
public function pimpable()
{
return $this->pimpable()
->addFilter('status', 'in', ['published', 'draft'])
->addSort('created_at');
}
$rules = config('api.filters.posts');
return Post::pimp($rules)->get();
Validation:
Validator):
$validated = request()->validate([
'filter.*.0' => 'sometimes|string',
'sort' => 'sometimes|array',
]);
Pagination:
return Post::pimp()->paginate(15);
GET /api/posts?with=user.address
like, between) via addOperator():
$this->pimpable()->addOperator('contains', function ($query, $field, $value) {
return $query->where($field, 'like', "%{$value}%");
});
// In middleware
$request->merge(['filter' => ['version' => 'v2']]);
Performance:
with[] params can trigger N+1 issues. Always eager-load relations explicitly.whereRaw or custom operators may bloat queries. Test with DB::enableQueryLog():
$query = Post::pimp();
$query->toSql(); // Inspect SQL
dd(DB::getQueryLog());
text) can be slow. Use database indexes or orderByRaw for complex sorts.Security:
$value = str_replace('%', '\%', request('filter.text'));
with[] params don’t enable unintended relation loading. Whitelist allowed relations:
protected $withable = ['user', 'comments']; // Only allow these
Edge Cases:
if (!request()->has(['filter', 'sort', 'with'])) {
return Post::all(); // Fallback
}
1/0 or true/false for clarity (e.g., filter[is_active]=1).Laravel Version Quirks:
HasApiTokens or Authorizable traits carefully—they may conflict with PimpableTrait.use Illuminate\Database\Eloquent\Model; (not Eloquent).\Log::info('Pimpable params:', [
'filter' => request('filter'),
'sort' => request('sort'),
'with' => request('with'),
]);
use PimpableTrait; to isolate issues.Post::pimp(['filter' => ['status' => 'published']])->get();
Custom Rules Provider: Create a service to dynamically load rules:
class FilterRuleProvider
{
public function getRules(string $model): array
{
return config("api.filters.{$model}");
}
}
Then use it in your model:
public function pimpable()
{
$rules = app(FilterRuleProvider::class)->getRules('Post');
return $this->pimpable()->addRules($rules);
}
Event Listeners:
Listen for pimpable.before and pimpable.after events to modify queries:
event(new PimpableEvent($query, $params));
Register in EventServiceProvider:
protected $listen = [
'pimpable.before' => [PimpableLogger::class],
];
API Documentation:
Auto-generate OpenAPI/Swagger docs by inspecting pimpable() rules:
# swagger.yaml
parameters:
- name: filter[status]
in: query
description: Filter by status (e.g., published,draft)
schema:
type: string
How can I help you explore Laravel packages today?