devaction-labs / filterable-package
A Laravel package for filterable traits and classes.
Requires
- php: ^8.2.0|^8.3.0
- illuminate/database: ^11.21
- illuminate/http: ^11.25
- illuminate/support: ^11.21
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- laravel/pint: ^1.13.7
- mockery/mockery: ^1.6
- pestphp/pest: ^2.35
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^10.5
- rector/rector: ^0.18.13
- roave/security-advisories: dev-latest
- symfony/var-dumper: ^6.4.0|^7.0.0
README
Filterable Package is a Laravel package designed to simplify filtering Eloquent models in your application. It provides an easy-to-use interface to apply various types of filters to your Eloquent queries, such as exact matches, partial matches (LIKE), date ranges, JSON-based filters, and more, directly from incoming requests. This package is especially useful for building APIs where dynamic filtering is often required.
Features
- Easy Integration: Apply the
Filterable
trait to your Eloquent models to start using it. - Multiple Filters: Supports a variety of filters such as exact matches, LIKE searches, greater than, less than, IN clauses, JSON-based filters, and date ranges.
- Custom Filter Mapping: Easily map request parameters to different column names in the database.
- Flexible Sorting: Allows for dynamic sorting of results based on request parameters.
Installation
To install the package, use Composer:
composer require devaction-labs/filterable-package
Usage
Step 1: Apply the Filterable
Trait to Your Model
Apply the Filterable
trait to any Eloquent model you want to filter.
namespace App\Models; use Illuminate\Database\Eloquent\Model; use DevactionLabs\FilterablePackage\Traits\Filterable; class Expense extends Model { use Filterable; // Define any custom filter map or allowed sorts if necessary protected array $filterMap = [ 'search' => 'description', // Example: map 'search' request parameter to 'description' column ]; protected array $allowedSorts = ['expense_date', 'amount']; // Example: allow sorting by these columns }
Step 2: Apply Filters in Your Controller
Apply filters in your controller methods using the filtrable
scope provided by the Filterable
trait.
namespace App\Http\Controllers\Api\Finance; use App\Http\Controllers\Controller; use App\Http\Resources\ExpenseCollection; use App\Models\Expense; use DevactionLabs\FilterablePackage\Filter; class ExpenseController extends Controller { public function index(): ExpenseCollection { $expenses = Expense::query() ->with(['category', 'period']) ->filtrable([ Filter::like('description', 'search'), Filter::exact('expense_date', 'date'), Filter::json('attributes', 'user.name', 'LIKE', 'user_name'), Filter::json('attributes', 'user.age', '>', 'user_age'), ]) ->customPaginate(); return new ExpenseCollection($expenses); } }
Available Filters
Filter::exact($attribute, $filterBy = null)
- Description: Filters records where the column value matches exactly with the provided value.
- Example:
Filter::exact('status', 'status')
filters records where thestatus
column matches the value of thestatus
parameter in the request.
Filter::like($attribute, $filterBy = null)
- Description: Filters records where the column value is similar to the provided value (uses SQL
LIKE
). - Example:
Filter::like('name', 'search')
filters records where thename
column contains the value of thesearch
parameter in the request.
Filter::in($attribute, $filterBy = null)
- Description: Filters records where the column value is within a specified list of values.
- Example:
Filter::in('category_id', 'categories')
filters records where thecategory_id
column matches any value provided in thecategories
parameter in the request.
Filter::gte($attribute, $filterBy = null)
- Description: Filters records where the column value is greater than or equal to the provided value.
- Example:
Filter::gte('amount', 'min_amount')
filters records where theamount
column is greater than or equal to the value of themin_amount
parameter in the request.
Filter::lte($attribute, $filterBy = null)
- Description: Filters records where the column value is less than or equal to the provided value.
- Example:
Filter::lte('amount', 'max_amount')
filters records where theamount
column is less than or equal to the value of themax_amount
parameter in the request.
Filter::json($attribute, $path, $operator = '=', $filterBy = null)
- Description: Filters records based on JSON attributes. Allows querying nested JSON data using a dot-notated path.
- Parameters:
$attribute
: The column that contains the JSON data.$path
: The dot-notated path to the JSON attribute (e.g.,'user.name'
).$operator
: The comparison operator (e.g.,'='
,'LIKE'
,'>'
, etc.).$filterBy
: The request parameter name to map to this filter.
- Example:
Filter::json('attributes', 'user.name', 'LIKE', 'user_name')
filters records where theuser.name
attribute in theattributes
JSON column matches theuser_name
request parameter using aLIKE
comparison.Filter::json('attributes', 'user.age', '>', 'user_age')
filters records where theuser.age
attribute in theattributes
JSON column is greater than theuser_age
request parameter.
Custom Filter Mapping
You can map request parameters to different column names in your database. For example:
protected array $filterMap = [ 'search' => 'description', 'date' => 'expense_date', ];
Now, if the request contains filter[search]=Pizza
, the query will filter the description
column for the value Pizza
.
Benefits and Differentiators
- Enhanced Code Readability: Filters are applied in a clean, readable manner without cluttering your controllers or models with complex query logic.
- Dynamic Filtering: Easily handle multiple filters from a single request without manually parsing input.
- Reusability: Filters can be reused across different queries and models, making your code DRY (Don't Repeat Yourself).
- Flexible Sorting: Allows sorting results dynamically based on request parameters, ensuring that your API remains flexible to client needs.
- JSON Support: Easily filter nested JSON attributes, enhancing the flexibility of your queries when dealing with JSON data types.
Example Usage in API Controller
public function index(): ExpenseCollection { $expenses = Expense::query() ->with(['category', 'period']) ->filtrable([ Filter::like('description', 'search'), Filter::exact('expense_date', 'date'), Filter::json('attributes', 'user.name', 'LIKE', 'user_name'), Filter::json('attributes', 'user.age', '>', 'user_age'), ]) ->customPaginate(); return new ExpenseCollection($expenses); }
Pagination and Sorting
Custom Pagination
Use the customPaginate
scope to apply pagination with customizable parameters.
$expenses = Expense::query() ->filtrable([...]) ->customPaginate(); // Defaults to 15 items per page // With custom parameters $expenses = Expense::query() ->filtrable([...]) ->customPaginate(false, ['per_page' => 10, 'sort' => '-amount']);
Allowed Sorts and Default Sort
Define allowed sorts and a default sort order in your model.
protected array $allowedSorts = ['expense_date', 'amount']; protected string $defaultSort = 'expense_date'; // In your controller $expenses = Expense::query() ->filtrable([...]) ->allowedSorts(['expense_date', 'amount']) ->customPaginate();
Handling JSON Filters with Different Databases
The package supports JSON-based filters across different database systems by handling the JSON extraction appropriately.
Supported Databases:
- MySQL: Uses the
->>
operator to extract JSON values. - SQLite: Uses the
json_extract
function. - PostgreSQL: Uses the
->>
operator to extract JSON values.
Ensure that your database driver is correctly set to utilize the appropriate JSON extraction method.
Conclusion
The Filterable Package simplifies the process of filtering Eloquent models in Laravel. By leveraging the power of this package, you can create highly flexible and dynamic filtering solutions in your application, improving code quality and maintainability. With support for JSON-based filters, you can efficiently query nested JSON attributes, making your APIs more robust and versatile.
License
This package is open-sourced software licensed under the MIT license.