victormgomes / query-params
Automatically generate query parameters from Eloquent models
Fund package maintenance!
Requires
- php: ^8.4
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/database: ^11.0||^12.0||^13.0
- illuminate/http: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
README
A powerful, zero-boilerplate package to handle complex API query parameters (filtering, sorting, field selection, relationship loading, and pagination) using native Laravel validation and optimized Eloquent queries.
🚀 Features
- Zero-Config Relations: Auto-maps
snake_casealiases and Foreign Keys for all Eloquent relationships. - Intelligent Queries: Automatically optimizes relationship filters to use FK columns for better DB performance.
- Strict Security: Native enforcement of Eloquent's
$visibleand$hiddenattributes. - Definitive Metadata: A specialized, deduplicated JSON structure for building dynamic frontend filters.
- Fancy URLs: Support for clean, "sentence-style" URL parameters.
- Native Validation: Auto-generates strict, type-safe Laravel validation rules from your database schema.
- Pluggable Drivers: Built-in support for complex field types like Translatable (JSON or Side-table).
📦 Installation
- Install the package via composer:
composer require victormgomes/query-params
- Publish the configuration file:
php artisan vendor:publish --tag="query-params-config"
⚡ Quick Start
Simply add the #[MapQueryParams] attribute and the HasQueryParams trait to your FormRequest:
use Victormgomes\QueryParams\Attributes\MapQueryParams; use Victormgomes\QueryParams\Concerns\HasQueryParams; use App\Models\User; #[MapQueryParams(User::class)] class IndexUserRequest extends FormRequest { use HasQueryParams; }
In your controller:
public function index(IndexUserRequest $request) { // The QueryBuilder uses the validated and normalized data automatically return QueryBuilder::build(User::class, $request); }
🛡️ Security & Visibility
The package strictly follows Laravel's internal visibility rules. Your API will never leak sensitive data because it respects:
$visible(Allow-list): If defined, only these fields will be exposed in metadata and available for query operations.$hidden(Deny-list): Fields in this array are strictly excluded from all operations.
🔗 Fancy URL Specification
The package supports "Sentence Style" parameters, allowing you to combine multiple operations into a single query key.
| Operation | URL Key | Fancy Sentence Format | Example |
|---|---|---|---|
| Filtering | filter |
field:operator:value |
?filter=name:like:Victor,active:true |
| Sorting | sort |
field:direction |
?sort=created_at:desc,name:asc |
| Fields | fields |
field1,field2 |
?fields=id,name,email |
| Includes | include |
relation1,relation2 |
?include=domains,active_tags |
| Pagination | page |
key:value |
?page=number:2,limit:50 |
Zero-Config Relationship Aliases
You don't need to worry about naming conventions. The package automatically discovers:
- Snake Case:
active_tagsin URL maps toactiveTags()in Model. - Foreign Keys:
people_idin URL maps topeople()relation. - Intelligent Filtering:
?filter=people:1is automatically optimized toWHERE people_id = 1.
Supported Filter Operators
| Operator | Description | URL Example |
|---|---|---|
eq |
Equal (Default) | status:active |
ne |
Not Equal | role:ne:admin |
like |
Case-sensitive search | name:like:John |
ilike |
Case-insensitive search | email:ilike:HOTMAIL |
gt / gte |
Greater than (or equal) | price:gt:100 |
lt / lte |
Less than (or equal) | age:lte:18 |
in / nin |
In list / Not in list | id:in:1,2,3 |
null / notnull |
Is Null / Is Not Null | deleted_at:null:true |
between |
Between two values | price:between:10,50 |
contains |
JSON/Array contains | tags:contains:urgent |
fts |
Full Text Search | content:fts:laravel |
🖥️ Frontend Dynamic Filters (Metadata)
The package provides a curated "Definitive Metadata" structure for frontend developers to build dynamic UI filters. It deduplicates aliases and only shows the most relevant names.
// In your controller or service return Resource::getDefinitiveMetadata(User::class);
Example JSON Response:
{
"model": "Contact",
"filters": {
"name": { "type": "string", "operations": ["eq", "like", "ilike"] },
"people": { "type": "relation_id", "operations": ["eq", "in"] }
},
"sorts": ["id", "name", "people"],
"includes": {
"people": { "related": "People", "type": "BelongsTo" },
"active_tags": { "related": "Tag", "type": "BelongsToMany" }
},
"pagination": {
"keys": ["number", "limit"],
"defaults": { "limit": 10, "max_limit": 100 }
}
}
🛠️ Advanced: Pluggable Drivers
Extend the package to handle custom database behaviors by defining a Resolver.
// config/query-params.php 'drivers' => [ 'translatable' => \App\Support\QueryDrivers\TranslationDriver::class, ],
Your driver must implement the Victormgomes\QueryParams\Contracts\FieldResolver interface to handle custom filtering, sorting, and output transformation.
⚖️ License
The MIT License (MIT). Please see License File for more information.