monterhealth/api-filter-bundle

REST API 过滤和排序包

安装次数: 20,221

依赖项: 1

建议者: 0

安全: 0

星标: 7

关注者: 3

分支: 6

开放问题: 0

类型:symfony-bundle

2.3.0 2024-09-10 22:08 UTC

README

MonterHealth ApiFilterBundle 使得在 Symfony 控制器类中轻松添加过滤和排序到 REST API 请求变得简单。受 API Platform 的过滤系统启发,但更专注于在控制器内的使用。

安装

使用 Symfony Flex 的应用程序

打开命令行控制台,进入您的项目目录,并执行以下命令

$ composer require monterhealth/api-filter-bundle

不使用 Symfony Flex 的应用程序

步骤 1: 下载 Bundle

打开命令行控制台,进入您的项目目录,并执行以下命令以下载此 Bundle 的最新稳定版本

$ composer require monterhealth/api-filter-bundle

此命令要求您全局安装 Composer,如 Composer 文档中的 安装章节 中所述。

步骤 2: 启用 Bundle

然后,通过将其添加到项目中 config/bundles.php 文件中注册的 Bundle 列表来启用 Bundle

<?php
// config/bundles.php

return [
// ...
    MonterHealth\ApiFilterBundle\MonterHealthApiFilterBundle::class => ['all' => true],
];

用法

首先定义可以使用的参数和过滤类型组合。这可以通过向实体类添加属性来实现。在控制器中加载 MonterHealth/ApiFilterBundle/MonterHealthApiFilter,并将其传递一个 Doctrine QueryBuilder、实体类名称和请求查询。它将请求查询的所有约束和排序添加到 QueryBuilder 中。

实体

向实体类添加属性。您可以在类级别或属性级别添加它们。该 Bundle 可以处理深层次的嵌套属性,如 author.name。

<?php
// src/Entity/Book.php

namespace App\Entity;

use MonterHealth\ApiFilterBundle\Attribute\ApiFilter;
use MonterHealth\ApiFilterBundle\Filter\BooleanFilter;
use MonterHealth\ApiFilterBundle\Filter\DateFilter;
use MonterHealth\ApiFilterBundle\Filter\OrderFilter;
use MonterHealth\ApiFilterBundle\Filter\RangeFilter;
use MonterHealth\ApiFilterBundle\Filter\SearchFilter;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\GeneratedValue;

#[ORM\Entity(repositoryClass: BookRepository::class)]
#[ApiFilter(BooleanFilter::class, properties: ["available"])]
#[ApiFilter(SearchFilter::class, properties: [
    "bookReferences.referencedBook.title"
])]
#[ApiFilter(SearchFilter::class, properties: [
    "title",
    "author" => OrderFilter::ASCENDING, // set the default order direction
    "pages" => OrderFilter::DESCENDING,
    "published"
])]
class Book
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255, nullable: true)]
    #[ApiFilter(SearchFilter::class)]
    private ?string $title = null;

    #[ORM\OneToMany(mappedBy: 'books', targetEntity: Author::class)]
    #[ApiFilter(SearchFilter::class)]
    private ?string $author = null;

    #[ORM\Column]
    #[ApiFilter(SearchFilter::class)]
    private ?int $pages = null;

    #[ORM\Column(type: Types::DATE_MUTABLE)]
    #[ApiFilter(DateFilter::class)]
    private ?\DateTimeInterface $published = null;

    #[ORM\Column]
    #[ApiFilter(OrderFilter::class, properties: [OrderFilter::DESCENDING])]
    private ?bool $available = null;

    #[ORM\OneToMany(mappedBy: 'book', targetEntity: BookReference::class)]
    private Collection $bookReferences;
// ...
}

控制器

使用自动装配在控制器中加载 MonterHealth/ApiFilterBundle/MonterHealthApiFilter 服务。

<?php
// src/Controller/BookController.php

namespace App\Controller;


use App\Repository\BookRepository;
use MonterHealth\ApiFilterBundle\MonterHealthApiFilter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;

class BookController extends AbstractController
{
    /**
     * @param Request $request
     * @param BookRepository $repository
     * @param MonterHealthApiFilter $monterHealthApiFilter
     * @return JsonResponse
     * @throws \ReflectionException
     */
    #[Route('books', name: 'get_books', methods: ["GET"])]
    public function getBooks(Request $request, BookRepository $repository, MonterHealthApiFilter $monterHealthApiFilter): JsonResponse
    {
        $queryBuilder = $repository->findAllQueryBuilder();
        $monterHealthApiFilter->addFilterConstraints($queryBuilder, $repository->getClassName(), $request->query);

        return new JsonResponse($queryBuilder->getQuery()->getArrayResult());
    }
}

过滤器

布尔过滤器

查询: parameter=<true|false|0|1>

例如

/books?available=true 显示所有可用的书籍。

搜索过滤器

可用策略

  • equals (默认)
  • partial
  • start
  • end
  • word_start
  • in
  • null

查询: parameter[strategy]=value 或 parameter[][strategy] 当对同一参数设置多个约束时。在策略前或后添加 [not] 以获取相反的过滤器效果。

例如

/books?author:name=agatha%20christie 返回所有作者为 'agatha christie' 的书籍。

/books?author[not][end]=rowling 返回所有不以 'rowling' 结尾的作者。

/books?author:author[in]=agatha%20christie|j.k.%20rowling 返回所有作者匹配 'agatha christie' 或 'j.k. rowling' 的书籍。

/books?title[][start]=harry&title[][not][word_start]=philosopher 返回所有标题以 'harry' 开头且标题中的单词不以 'philosopher' 开头的书籍。

/books?title[null] 返回所有标题为空的书籍。null 策略不需要任何额外的值。

in 策略包括包含 NULL 值的选项。例如

/books?author:id[in]=48|24|NULL 返回所有作者 ID 匹配 48 或 24 的书籍,以及所有未设置作者的书籍。

/books?author:id[not][in]=48|24|NULL 返回所有作者 ID 不匹配 48 和 24 的书籍,以及所有未设置作者的书籍。

如您所注意到的,嵌套属性必须使用冒号(:)进行引用,例如在uri中使用author:name。

排序过滤器

可用策略

  • 升序
  • 降序

查询:order_parameter_name[strategy]=parameter 或 order_parameter_name[][strategy]=parameter 允许多个排序。

例如

/books?order=author:name 按作者默认方向(升序)或实体设置的顺序对列表进行排序。

/books?order[desc]=author:name 按作者降序对列表进行排序。

/books?order[][asc]=author:name&order[][asc]=title 按作者升序排序,并按标题升序排序。

数字过滤器

查询:parameter=value

例如

/books?stock=10 返回所有库存为10的书籍。

范围过滤器

可用策略

  • gt(大于)
  • lt(小于)
  • gte(大于等于)
  • lte(小于等于)
  • bt(介于)
  • equals(等于)

查询:parameter[strategy]=value 或 parameter[][strategy]=value 当对同一参数设置多个约束时。

例如

/books?stock[lte]=10 返回所有库存小于等于10的书籍。

/books?stock[bt]=0|10 返回所有库存介于0和10之间的书籍。

日期过滤器

可用策略

  • before(<=)
  • after(>=)
  • strictly_before(<)
  • strictly_after(>)
  • equals(=)(默认)
  • null_or_before
  • null_or_after
  • null_or_strictly_before
  • null_or_strictly_after
  • null

查询:parameter[strategy]=value 或 parameter[][strategy]=value 当对同一参数设置多个约束时。

例如

books?createdAt[before]=2020-12-04 返回所有 createdAt <= 2020-12-04 的书籍。

books?createdAt[][after]=2020-12-01&createdAt[][before]=2020-12-04 返回所有 createdAt >= 2020-12-01 且 <= 2020-12-04 的书籍。

配置

monter_health_api_filter:
    # The name of the query parameter to order results.
    order_parameter_name: 'order'
    # The default order strategy (ascending or descending).
    default_order_strategy: 'ascending'
    # Possibility to override the default ParameterCollectionFactory.
    parameter_collection_factory: ~
    # Possibility to override the default attribute reader.
    attribute_reader: ~
    # Possibility to override the default ApiFilterFactory.
    api_filter_factory: ~

# Add a custom filter:
services:
    CustomFilter:
        tags: [monter_health_api_filter]

升级到版本2

为了升级到版本2,建议使用 rector。添加配置规则将 ApiFilter 注释转换为属性。

$rectorConfig->ruleWithConfiguration(AnnotationToAttributeRector::class, [
    new AnnotationToAttribute('ApiFilter'),
]);