monterhealth / api-filter-bundle
REST API 过滤和排序包
Requires
- php: ^8.0
- symfony/orm-pack: *
Requires (Dev)
- symfony/phpunit-bridge: ^4.1
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'), ]);