定制 silpo-tech/filter-bundle 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

silpo-tech/filter-bundle

Composer 安装命令:

composer require silpo-tech/filter-bundle

包简介

Common Filter bundle

README 文档

README

CI codecov License: MIT

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

  1. 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
        );
    }
}
  1. 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:

  • exact strategy uses IN (...) to search for fields that contain value1, value2, ..., valueN.
  • partial strategy uses LIKE %text% to search for fields that contain text.
  • start strategy uses LIKE text% to search for fields that start with text.
  • end strategy uses LIKE %text to search for fields that end with text.
  • word_start strategy uses LIKE text% OR LIKE % text% to search for fields that contain words starting with text.

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 — adds IS NOT NULL condition, completely excluding records where the date field is null.
  • include_null_before — when filtering with to/strictly_to, records with null are included in the results (treated as oldest).
  • include_null_after — when filtering with from/strictly_from, records with null are included in the results (treated as youngest).
  • include_null_before_and_after — records with null are 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 我们能提供哪些服务?
定制开发 / 二次开发

基于 silpo-tech/filter-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.89k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: proprietary
  • 更新时间: 2025-10-02