silpo-tech/filter-bundle
Composer 安装命令:
composer require silpo-tech/filter-bundle
包简介
Common Filter bundle
README 文档
README
About
The Filter Bundle contains mapping and criteria builder
Installation
Require the bundle and its dependencies with composer:
$ composer require silpo-tech/filter-bundle
Register the bundle:
// app/AppKernel.php public function registerBundles() { $bundles = array( new FilterBundle\FilterBundle(), ); }
Usage
- Action:
namespace App\Controller; use App\DTO\Request\Location\LocationFilter; use App\DTO\Request\Location\LocationOrder; use FilterBundle\Request\FilterValueResolver; use PaginatorBundle\Paginator\OffsetPaginator; use PermissionBundle\Configuration\Permissions; use RestBundle\Controller\RestController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use FilterBundle\Annotation\FilterMapper; class ListAction { public function __construct(private readonly LocationRepository $repository) { } #[Route(path: 'v1/action/entities', name: ListAction::class, methods: [Request::METHOD_GET])] public function all( #[FilterMapper] LocationFilter $filter, #[FilterMapper] LocationSort $order, OffsetPaginator $offsetPaginator ): Response { return $this->createPaginatedResponse( $this->repository->findWithConditions($filter, $order), $offsetPaginator, LocalizedLocationDto::class ); } }
- Repository method
namespace App\Repository; use App\DTO\Request\Location\LocationFilter; use App\DTO\Request\Location\LocationOrder; use App\Entity\Location; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; use FilterBundle\Bridge\Doctrine\Orm\Util\QueryNameGenerator; use FilterBundle\Service\ConditionBuilder; use Hubber\LazyLib\EntityCollection; class EntityRepository extends ServiceEntityRepository { public const ALIAS = 'entity'; public function __construct(ManagerRegistry $registry, private ConditionBuilder $conditionBuilder) { parent::__construct($registry, Entity::class); } public function findWithConditions(EntityDTOFilter $filter): EntityCollection { $queryNameGenerator = new QueryNameGenerator(); $qb = $this->createQueryBuilder(self::ALIAS); $this->conditionBuilder->applyFilters($qb, $queryNameGenerator, $this->getClassName(), $filter); return new EntityCollection($qb); } }
Filter DTO example:
namespace App\Dto\Request\Entity; use FilterBundle\Annotation\ApiFilter; use FilterBundle\Bridge\Doctrine\Orm\BooleanFilter;use FilterBundle\Bridge\Doctrine\Orm\SearchFilter; use FilterBundle\Bridge\Doctrine\Orm\LocaleFilter; use FilterBundle\Bridge\Doctrine\Orm\OrderFilter; use FilterBundle\Validator\Constraints\ValidDateRange; use FilterBundle\Validator\Constraints\DateRangeBeforeGreaterThanAfter; use FilterBundle\Validator\Constraints\DateRangeBeforeNotEqualsAfter; use Symfony\Component\Validator\Constraints as Assert; #[ApiFilter(LocaleFilter::class, property: 'translations.locale')] class EntityDTOFilter { #[ApiFilter(SearchFilter::class, property: 'parents.id', strategy: SearchFilter::STRATEGY_EXACT)] #[Assert\Uuid] /** @var string */ public $parentId; #[Assert\Sequentially(constraints: [ new Assert\Type(type: 'string'), new Assert\Uuid(versions: [Assert\Uuid::V6_SORTABLE]), ])] #[ApiFilter(SearchFilter::class, property: 'nullableId', strategy: 'exact')] #[ApiFilter(NullFilter::class, property: 'nullableId')] /** @var string|null */ public $nullableId = null; #[ApiFilter(BooleanFilter::class)] /** @var boolean */ public $active = true; #[Assert\Sequentially( constraints: [ new Assert\NotBlank(), new Assert\Choice(callback: [EntityStatus::class, 'getChoices'], multiple: true) ] )] #[ApiFilter(SearchFilter::class, property: 'status', strategy: SearchFilter::STRATEGY_EXACT)] /** @var array */ public $status = []; #[ApiFilter(DateFilter::class, property: 'createdAt')] #[ValidDateRange(format: 'Y-m')] #[DateRangeBeforeGreaterThanAfter] #[DateRangeBeforeNotEqualsAfter] /** @var array */ public $createdAt = []; #[Assert\Type('array')] #[ApiSort( filterClass: OrderFilter::class, map: ['id' => 'id', 'status' => 'status', 'createdAt' => 'createdAt', 'updatedAt' => 'updatedAt'] )] /** @var string[] */ public $sort = ['-id']; }
Search Filter
If Doctrine ORM or MongoDB ODM support is enabled, adding filters is as easy as registering a filter service in the
api/config/services.yaml file and adding an attribute to your resource configuration.
The search filter supports exact, partial, start, end, and word_start matching strategies:
exactstrategy usesIN (...)to search for fields that containvalue1, value2, ..., valueN.partialstrategy usesLIKE %text%to search for fields that containtext.startstrategy usesLIKE text%to search for fields that start withtext.endstrategy usesLIKE %textto search for fields that end withtext.word_startstrategy usesLIKE text% OR LIKE % text%to search for fields that contain words starting withtext.
Prepend the letter i to the filter if you want it to be case insensitive. For example ipartial or iexact. Note
that
this will use the LOWER function and will impact
performance if there is no proper index.
Case insensitivity may already be enforced at the database level depending on
the collation
used. If you are using MySQL, note that the commonly used utf8_unicode_ci collation (and its
sibling utf8mb4_unicode_ci)
are already case-insensitive, as indicated by the _ci part in their names.
You can dynamically change the strategy to filters from the client, for this behavior your dto must implement
StrategyInterface:
?filter[title:istart]=Ukrainian
Example syntax for exact strategy:
?filter[status][0]=new&filter[status][1]=completed
Date Filter
Usage syntax: ?filter[createdAt][from]=2022-05&filter[createdAt][to]=2022-06
Managing null Values
The date filter is able to deal with date properties having null values.
Four behaviors are available at the property level of the filter via the arguments parameter:
| Description | Strategy to set |
|---|---|
| Use the default behavior of the DBMS | null (default) |
| Exclude items | exclude_null |
| Consider items as oldest | include_null_before |
| Consider items as youngest | include_null_after |
| Always include items | include_null_before_and_after |
To configure null management for a date property, pass the nullManagement key in the arguments array of the #[ApiFilter] attribute:
use FilterBundle\Annotation\ApiFilter; use FilterBundle\Bridge\Doctrine\Orm\DateFilter; class EntityDTOFilter { #[ApiFilter(DateFilter::class, property: 'deletedAt', arguments: ['nullManagement' => 'exclude_null'])] /** @var array */ public $deletedAt = []; #[ApiFilter(DateFilter::class, property: 'archivedAt', arguments: ['nullManagement' => 'include_null_before_and_after'])] /** @var array */ public $archivedAt = []; }
Behavior details:
exclude_null— addsIS NOT NULLcondition, completely excluding records where the date field isnull.include_null_before— when filtering withto/strictly_to, records withnullare included in the results (treated as oldest).include_null_after— when filtering withfrom/strictly_from, records withnullare included in the results (treated as youngest).include_null_before_and_after— records withnullare always included regardless of the filter direction.
You can also combine nullManagement with other DateFilter arguments like compareDateToDateTime or convertToTz:
#[ApiFilter(DateFilter::class, property: 'createdAt', arguments: [ 'nullManagement' => 'include_null_after', 'convertToTz' => 'UTC', ])] public $createdAt = [];
Order Filter (Sorting)
The order filter allows to sort a collection against the given properties.
Syntax: ?filter[sort][0]=-createdAt&filter[sort][0]=updatedAt
By default, whenever the query does not specify the direction explicitly (e.g.: ?filter[sort][0]=-createdAt), filters
will not be applied unless you configure a default order direction to use.
Constraints
ValidDateRange
Validates that given array value is a valid date range, e.g. property is an array with two keys: from, to; array values should date string of valid format, default format is Y-m-d
Basic usage
use FilterBundle\Validator\Constraints\DateRange; class FilterDTO { #[DateRange(format: DateTimeInterface::ATOM)] /** @var string[] */ public $createdAt = []; }
use FilterBundle\Validator\Constraints\DateRange; class FilterDTO { #[DateRange( format: DateTimeInterface::ATOM, min: '+1 sec', max: '+23 day 4 hour', )] /** @var string[] */ public $createdAt = []; }
Options
format
Defines date string format
invalidDateTimeMessage
Message that will be shown if from or to values are not valid date string
invalidDateRangeMessage
Message that will be shown if from is greater than to
min
If provided additional check will be performed to check to is greater than from for at least min
value. Value should be valid DateInterval string with leading plus sign, e.g. +1 sec, +2 hour 3 min.
max
If provided additional check will be performed to check to is greater than from for at most max
value. Value should be valid DateInterval string with leading plus sign, e.g. +1 sec, +2 hour 3 min.
minMessage
Message that will be shown if to is not greater than from for at least min value
maxMessage
Message that will be shown if to is greater than from for more than max value
silpo-tech/filter-bundle 适用场景与选型建议
silpo-tech/filter-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.89k 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 10 月 02 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 silpo-tech/filter-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 silpo-tech/filter-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 1.89k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: proprietary
- 更新时间: 2025-10-02