Clean query building using Criteria
Criteria is a framework-agnostic PHP package that simplifies the use of the criteria pattern for filtering, sorting, and paginating data. It helps separate query logic from repositories, making the codebase easier to maintain and extend over time. By using Criteria, developers can handle complex querying needs without spreading filter logic across different parts of the application.
The package has recently been updated with several improvements. It now includes a cleanup of unused classes and files, a clearer usage structure, and the use of readonly
classes to take advantage of PHP language features that improve safety and consistency. These changes make the package easier to work with, reduce potential bugs, and offer a more stable and consistent experience during development.
Prerequisites
Take a look on how to install Composer 2 on your computer to manage packages and its dependencies.
Installation
Assuming that Composer is already installed, you can include the package using Composer:
composer require hibit-dev/criteria
Generating criteria
A specific criteria must be created for each use case. It extends the shared domain logic found in the abstract Criteria
implementation, which standardizes how filtering, sorting, and pagination are applied. This ensures that each query follows a consistent pattern while allowing flexibility for different filtering needs.
In this example, UserSearchCriteria
is designed to handle filtering by name
and email
, while accepting CriteriaPagination
and CriteriaSort
to manage pagination and sorting. The static create()
method builds a fully constructed criteria object.
use Hibit\\Criteria;
use Hibit\\CriteriaPagination;
use Hibit\\CriteriaSort;
final readonly class UserSearchCriteria extends Criteria
{
public ?string $name;
public ?string $email;
public static function create(
CriteriaPagination $pagination,
CriteriaSort $sort,
?string $name = null,
?string $email = null,
): UserSearchCriteria {
$criteria = new self($pagination, $sort);
$criteria->name = $name;
$criteria->email = $email;
return $criteria;
}
}
Marking the class as readonly
ensures that the criteria object cannot be modified after creation, maintaining consistency and preventing unwanted changes during processing.
Pagination
The CriteriaPagination
class is responsible for managing pagination. The create()
method is used to easily construct a pagination object, where you can specify the limit and offset values (defaulting to 10 and 0 if not specified).
// Default Pagination: limit=10, offset=0
CriteriaPagination::create()
// Pagination: limit=10 (default), offset=10
CriteriaPagination::create(null, 10)
// Pagination: limit=20, offset=0 (default)
CriteriaPagination::create(20)
// Pagination: limit=20, offset=20
CriteriaPagination::create(20, 20)
The first value represents the limit
(items per page), and the second value represents the offset
(the starting point for the results). This approach ensures flexibility and ease of use when handling pagination in queries.
Sorting
The CriteriaSort
class manages the sorting of query results. It works with the create()
method to specify the field by which to sort the results, as well as the sorting direction (ascending or descending).
// Sorting: created_at DESC (default)
CriteriaSort::create('created_at')
// Sorting: created_at ASC
CriteriaSort::create('created_at', CriteriaSortDirection::ASC)
// Sorting: name DESC
CriteriaSort::create('name', CriteriaSortDirection::DESC)
This class helps maintain a consistent sorting approach throughout the application.
Integrating Criteria
Once a custom criteria class is defined, it can be passed into the repository to filter, sort, and paginate the data accordingly. The repository is where the actual query-building happens, using the criteria object to structure the database query. This keeps the filtering, sorting, and pagination logic separate from the rest of the application, making the code cleaner and easier to maintain.
use Hibit\\CriteriaPagination;
use Hibit\\CriteriaSort;
use Hibit\\CriteriaSortDirection;
class UserRepository
{
public function searchByCriteria(UserSearchCriteria $criteria): array
{
// Start query builder to apply filtering
if ($criteria->name !== null) {
// Apply name filter: $criteria->name
}
if ($criteria->email !== null) {
// Apply email filter: $criteria->email
}
if ($criteria->pagination !== null) {
// Apply limit: $criteria->pagination->limit
// Apply offset: $criteria->pagination->offset
}
if ($criteria->sort) {
// Apply sorting field: $criteria->sort->field->value()
// Apply sorting direction: $criteria->sort->direction->value()
}
// Execute the query and return the results
}
}
Note that all values can be nullable when constructing the query within the repository.
Using Criteria
To use the criteria in your repository, create an instance of the criteria class with the necessary filters, pagination, and sorting. Then, pass the criteria object to the repository method, which will apply it to the query.
use Hibit\\CriteriaPagination;
use Hibit\\CriteriaSort;
use Hibit\\CriteriaSortDirection;
class CriteriaTestClass
{
public function __invoke(UserRepository $userRepository): array
{
return $userRepository->searchByCriteria(
UserSearchCriteria::create(
CriteriaPagination::create(), // Default pagination
CriteriaSort::create('created_at', CriteriaSortDirection::DESC),
'John'
)
);
}
}
This approach ensures that filtering, sorting, and pagination are easily maintained and reused throughout the application.
Conclusion
The updated criteria package provides a cleaner, more modern way to manage query parameters in PHP. By relying on readonly
classes, simplified structure, and improved defaults, it helps teams reduce boilerplate, avoid bugs, and keep code focused.
Credits
Official GitHub: https://github.com/hibit-dev/criteria
0 Comments