- How do I enable filtering for a specific Eloquent model in a Laravel API endpoint?
- Use `QueryBuilder::for(Model::class)->allowedFilters(['field1', 'field2'])->get()` in your controller. For partial matches, specify `AllowedFilter::partial('field')`. Example: `QueryBuilder::for(User::class)->allowedFilters(AllowedFilter::partial('name'))->get()`. This handles requests like `/users?filter[name]=John` safely.
- Can I use this package with Laravel 8.x or older versions?
- No, this package requires Laravel 9+ due to dependencies on newer Eloquent features. If you’re on Laravel 8 or older, check the GitHub issues for alternatives or consider upgrading. The package explicitly drops support for older versions.
- How do I prevent SQL injection when using dynamic query parameters?
- The package enforces whitelisting via `allowedFilters()`, `allowedSorts()`, and `allowedIncludes()`. Only explicitly allowed fields are processed. For example, `allowedFilters(['email', 'status'])` restricts input to those fields, blocking arbitrary SQL injection attempts.
- Does this package support nested relationships (e.g., includes like `?include=posts.comments`)?
- Yes, use `allowedIncludes(['posts', 'posts.comments'])` to enable nested eager loading. The package follows Laravel’s `with()` syntax and supports dot notation for deep relationships. Example: `QueryBuilder::for(User::class)->allowedIncludes('posts')->get()`.
- How can I apply default values to query parameters (e.g., default sorting or filters)?
- Use `defaultSorts(['created_at', 'desc'])` or `defaultFilters(AllowedFilter::exact('status', 'active'))`. These apply when no query parameters are provided. Example: `QueryBuilder::for(Product::class)->defaultSorts(['price', 'asc'])->get()` ensures `/products` sorts by price ascending by default.
- Will this package work with Laravel Policies or Gates for authorization?
- Yes, the package integrates seamlessly with Laravel’s authorization system. Use `QueryBuilder::for(User::class)->allowedFilters(['name'])->where(function ($query) { $query->where('active', true); })->get()` to combine dynamic queries with policy checks. The query builder respects all Eloquent constraints.
- How do I test API endpoints using this package for edge cases (e.g., invalid filters or malformed requests)?
- Test with `Http::fake()` and `QueryBuilder::for(Model::class)->allowedFilters(['field'])->get()`. Mock requests like `filter[field]=%` or `sort=invalid` to verify whitelisting works. Use PHPUnit assertions to check returned data matches expected constraints.
- Can I use custom filters beyond basic partial/exact matches (e.g., date ranges or custom scopes)?
- Absolutely. Implement the `AllowedFilter` interface or use `AllowedFilter::custom('scope_name')` to map query parameters to Eloquent scopes. Example: `allowedFilters(AllowedFilter::custom('active'))` triggers a `scopeActive()` method on your model.
- How do I integrate this into all API routes without repeating code in every controller?
- Create middleware: `public function handle(Request $request, Closure $next) { $response = $next($request); if ($request->is('api/*')) { $response->header('X-Query-Builder', 'Enabled'); } return $response; }`. Then use `QueryBuilder::for(Model::class)` in routes or controllers.
- What’s the performance impact of dynamic includes or complex sorts on large datasets?
- Nested includes or custom sorts can cause N+1 queries or slow SQL. Mitigate by using `with()` for default includes and `constrain()` to limit results early. Example: `QueryBuilder::for(Product::class)->allowedIncludes('reviews')->constrain(fn ($query) => $query->where('price', '>', 10))->get()`. Monitor with Laravel Debugbar or query logging.