api-skeletons/doctrine-orm-querybuilder-filter

使用filter[fieldName|operator]=value对QueryBuilder进行过滤

2.0.1 2023-10-21 14:23 UTC

This package is auto-updated.

Last update: 2024-09-21 21:06:51 UTC


README

Build Status Code Coverage PHP Version Total Downloads License

根据请求参数对QueryBuilder应用过滤器。支持使用连接进行深度查询。此存储库旨在将查询参数应用于过滤实体数据。

安装

运行以下命令使用Composer安装此库

composer require api-skeletons/doctrine-orm-querybuilder-filter

快速入门

use ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator;

$applicator = new Applicator($entityManager, Entity\User::class);
$queryBuilder = $applicator($_REQUEST['filter']);

过滤器

创建过滤器的模式为filter[fieldName|operator]=value这种模式是定义复杂查询的一种简单方式,利用QueryBuilder的所有过滤功能。

以下URL将为用户的name提供LIKE过滤器

http://localhost/api/user?filter[name|like]=John

支持以下运算符

  • eq - 等于。如果没有指定运算符,则这是默认值
  • neq - 不等于
  • gt - 大于
  • gte - 大于或等于
  • lt - 小于
  • lte - 小于或等于
  • between - 两个值之间的范围,逗号分隔,例如filter[id|between]=1,5
  • like - 模糊搜索,用通配符包装值
  • startswith - 带右通配符的like运算符
  • endswith - 带左通配符的like运算符
  • in - 要匹配的值列表,逗号分隔,例如filter[id|in]=1,2,3]
  • notin - in运算符的相反
  • isnull - 任何值都接受;将检查字段是否为空
  • isnotnull - isNull运算符的相反
  • sort - 根据字段排序结果,可以是ascdesc

您可以使用任意数量的过滤器。过滤器作用于实体的字段名称和关联名称。这允许您对关联进行过滤。例如,要按已知公司ID和正确的Doctrine元数据过滤用户列表,您可以像这样过滤

http://localhost/api/user?filter[company]=10

因此,即使没有名为公司的字段,也存在一个关联,并且可以通过此工具进行过滤。

对单个实体进行过滤

Applicator的配置允许您启用关联过滤,但默认情况下是禁用的。所以,假设默认设置,这是一个对单个实体的复杂过滤

http://localhost/api/user?filter[company|neq]=15&filter[name]=John

对实体层次结构进行过滤

Applicator的配置允许您启用关联过滤。这意味着您可以根据与当前实体关联的字段对当前实体进行过滤,并且您可以做到您想要的深度。

在这个例子中,我们将根据他们的公司名称获取用户数据

http://localhost/api/user?filter[company][name|eq]=AAA

在这个例子中,我们将根据公司的公司类型和公司类型名称获取用户数据

http://localhost/api/user?filter[company][companyType][name|neq]=Consultant

在您过于担心此功能之前,请记住您可以在应用过滤器之后修改QueryBuilder,因此如果您需要应用安全设置,这是支持的。

关于排序的说明

虽然排序在严格意义上不是过滤器,但在请求数据时它属于同一上下文。您可以按多个字段排序,并且可以跨关联排序(如果启用)。排序优先级从左到右。

使用

这是使用此库所需的最小配置

use ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator;

$applicator = (new Applicator($entityManager, Entity\User::class));
$queryBuilder = $applicator($_REQUEST['filter']);

这是一个配置应用器的所有可能选项的示例

use ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator;

$applicator = (new Applicator($entityManager, Entity\User::class))
    ->enableRelationships()
    ->removeOperator('like')
    ->setEntityAlias('user')
    ->setFieldAliases(['firstName' => 'name'])
    ->setFilterableFields(['id', 'name'])
    ;
$queryBuilder = $applicator($_REQUEST['filter']);

$entityAliasMap = $applicator->getEntityAliasMap();

在应用过滤器后返回QueryBuilder之后,您可以在使用它来获取结果之前按需对其进行修改。

现实世界的Laravel示例

在这个示例中,使用HAL在控制器操作中返回分页响应,其中包含来自Entity\Style实体的数据。

use ApiSkeletons\Doctrine\QueryBuilder\Filter\Applicator;
use Doctrine\ORM\Tools\Pagination\Paginator;
use HAL;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;


public function fetchAll(Request $request)
{
    $filter = $request->query()['filter'] ?? [];
    if (! is_array($filter)) {
        $filter = [];
    ]
    
    $page = (int) $request->query()['page'] ?? 1;
    if ($page < 1) {
        $page = 1;
    }

    $applicator = (new Applicator(app('em'), Entity\Style::class))
        ->enableRelationships(true);
    $queryBuilder = $applicator($filter);

    $paginator = new Paginator($queryBuilder);
    $paginator->getQuery()
        ->setFirstResult(25 * ($page - 1)) // Page is 0 indexed in query
        ->setMaxResults(25)
        ;

    $data = (new LengthAwarePaginator(iterator_to_array($paginator->getIterator()), $paginator->count(), 25))
        ->appends($request->query())
        ->withPath(route('api.style::fetchAll'))
        ;

    return HAL::paginate('style', $data)->toArray();
}

配置

使用Applicator很简单,它提供了许多配置选项。首先创建Applicator,然后运行配置函数

$applicator = new Applicator($entityManager, Entity\Style::class);

enableAssociations()

此配置方法通过使用Doctrine元数据来遍历ORM,通过现有的连接到目标实体的连接来实现深度过滤。这仅在具有完整元数据和在元数据中定义的实体之间适当的关联的Doctrine安装中才可行。

removeOperator(string|array)

如果您想禁用任何操作符,可以将其删除。一个好的例子是like操作符,它可能导致昂贵的查询。

setEntityAlias(string)

在QueryBuilder中为目标实体创建过滤器时使用的默认别名是entity。您可能想更改它,以便在QueryBuilder返回后知道别名,并可以向其中添加更多参数。

setFieldAliases(array)

如果您想使过滤器将字段别名为而不是使用ORM字段名称(例如在hydrators中使用命名策略),您可以传递一个包含[alias => field]值的数组,以便调整映射。

setFilterableFields(array)

默认情况下,可以对目标实体的所有字段进行筛选。如果您想限制用户可以创建筛选器的字段,请在此数组中传递那些字段名称。

getEntityAliasMap()

此方法用于目标实体的后处理。当用户使用enableAssociations()进行深度筛选时,将为与原始实体查询连接的每个实体创建别名。此方法返回一个包含所有在QueryBuilder中连接的实体的[alias => entityClass]的数组。