artprima / query-filter-bundle
在您的 Symfony 4/5/6 应用程序(使用 Doctrine2 作为 ORM)中过滤请求的简单方法。
1.8.0
2022-10-09 06:42 UTC
Requires
- php: >=8.0.0
- doctrine/doctrine-bundle: ^2.2
- doctrine/orm: ^2.7
- doctrine/persistence: ^2.0|^3.0
- sensio/framework-extra-bundle: ^5.1.5|^6.0
- symfony/config: ^4.4|^5.2|^6.0
- symfony/dependency-injection: ^4.4|^5.2|^6.0
- symfony/http-kernel: ^4.4|^5.2|^6.0
Requires (Dev)
- phpunit/phpunit: ^8.0|^9.0
README
Symfony 4.4、Symfony 5 和 Symfony 6 的查询过滤包
查询过滤包为使用 Doctrine 2 的 Symfony 4.4 / 5 / 6 应用程序提供了请求过滤和分页功能。
安装
首先,安装依赖项
$ composer require artprima/query-filter-bundle
使用示例
基本示例
- 控制器
<?php namespace App\Controller; use Artprima\QueryFilterBundle\QueryFilter\Config\BaseConfig; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Component\HttpFoundation\Request as HttpRequest; use Artprima\QueryFilterBundle\Request\Request; use Artprima\QueryFilterBundle\QueryFilter\QueryFilter; use Artprima\QueryFilterBundle\Response\Response; use App\Repository\ItemRepository; class DefaultController extends Controller { // ... /** * @Route("/") */ public function indexAction(HttpRequest $request, ItemRepository $repository) { // set up the config $config = new BaseConfig(); $config->setSearchAllowedCols(['t.name']); $config->setSearchAllowedColsLengths(['t.name' => ['min' => 2, 'max' => 255]]); $config->setAllowedLimits([10, 25, 50, 100]); $config->setDefaultLimit(10); $config->setSortCols(['t.id'], ['t.id' => 'asc']); $config->setRequest(new Request($request)); // Throws an UnexpectedValueException when invalid filter column, sort column or sort type is specified $config->setStrictColumns(true); // here we provide a repository callback that will be used internally in the QueryFilter // The signature of the method must be as follows: function functionName(QueryFilterArgs $args): QueryResult; $config->setRepositoryCallback([$repository, 'findByOrderBy']); // Response must implement Artprima\QueryFilterBundle\Response\ResponseInterface $queryFilter = new QueryFilter(Response::class); /** @var Response $data the type of the variable is defined by the class in the first argument of QueryFilter's constructor */ $response = $queryFilter->getData($config); $data = $response->getData(); $meta = $response->getMeta(); // ... now do something with $data or $meta } // ... }
- 仓库
<?php namespace App\Repository; use App\Entity\Item; use Artprima\QueryFilterBundle\Query\ConditionManager; use Artprima\QueryFilterBundle\QueryFilter\QueryFilterArgs; use Artprima\QueryFilterBundle\QueryFilter\QueryResult; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\Tools\Pagination\Paginator; use Symfony\Bridge\Doctrine\RegistryInterface; class ItemRepository extends ServiceEntityRepository { /** * @var ConditionManager */ private $pqbManager; public function __construct(RegistryInterface $registry, ConditionManager $manager) { parent::__construct($registry, Item::class); $this->pqbManager = $manager; } public function findByOrderBy(QueryFilterArgs $args): QueryResult { // Build our request $qb = $this->createQueryBuilder('t') ->setFirstResult($args->getOffset()) ->setMaxResults($args->getLimit()); $proxyQb = $this->pqbManager->wrapQueryBuilder($qb); $qb = $proxyQb->getSortedAndFilteredQueryBuilder($args->getSearchBy(), $args->getSortBy()); $query = $qb->getQuery(); $paginator = new Paginator($query); // return the wrapped result return new QueryResult($paginator->getIterator()->getArrayCopy(), count($paginator)); } // ... }
现在您可以启动您的 PHP 服务器并过滤请求
GET http://127.0.0.1:8000/?filter[t.name]=Doe&limit=100
此请求将在 DQL 中执行 LIKE 请求
SELECT t FROM Item WHERE t.name LIKE "%Doe%" LIMIT 100
高级示例
此过滤库最好与 JMSSerializerBundle 和 FOSRestBundle 一起使用。您最终编写的代码将比基本示例中的代码少得多。
要利用高级用法,安装所有包。
composer require friendsofsymfony/rest-bundle composer require jms/serializer-bundle composer require artprima/query-filter-bundle
- 在
config/bundles.php
中启用它们
<?php return [ // ... Artprima\QueryFilterBundle\ArtprimaQueryFilterBundle::class => ['all' => true], FOS\RestBundle\FOSRestBundle::class => ['all' => true], JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], // ... ];
注意:您可能需要根据您的设置为 FOSRestBundle 和/或 JMSSerializerBundle 添加更多包。
- 控制器
<?php namespace App\Controller; use App\QueryFilter\Response; use App\Repository\ItemRepository; use Artprima\QueryFilterBundle\QueryFilter\Config\ConfigInterface as QueryFilterConfigInterface; use FOS\RestBundle\Controller\Annotations as Rest; use FOS\RestBundle\Controller\FOSRestController; use FOS\RestBundle\Routing\ClassResourceInterface; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Artprima\QueryFilterBundle\Controller\Annotations\QueryFilter; class ItemController extends FOSRestController implements ClassResourceInterface { /** * @Rest\View(serializerEnableMaxDepthChecks=true) * @ParamConverter("config", class="App\QueryFilter\Config\ItemConfig", * converter="query_filter_config_converter", * options={"entity_class": "App\Entity\Item", "repository_method": "findByOrderBy"}) * @QueryFilter() * @Rest\Get("/items") */ public function cgetAction(QueryFilterConfigInterface $config) { return $config; } }
- 仓库
<?php namespace App\Repository; use App\Entity\Item; use Artprima\QueryFilterBundle\Query\ConditionManager; use Artprima\QueryFilterBundle\QueryFilter\QueryFilterArgs; use Artprima\QueryFilterBundle\QueryFilter\QueryResult; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\Tools\Pagination\Paginator; use Symfony\Bridge\Doctrine\RegistryInterface; /** * @method Item|null find($id, $lockMode = null, $lockVersion = null) * @method Item|null findOneBy(array $criteria, array $orderBy = null) * @method Item[] findAll() * @method Item[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ class ItemRepository extends ServiceEntityRepository { /** * @var ConditionManager */ private $pqbManager; public function __construct(RegistryInterface $registry, ConditionManager $manager) { parent::__construct($registry, Item::class); $this->pqbManager = $manager; } public function findByOrderBy(QueryFilterArgs $args): QueryResult { $qb = $this->createQueryBuilder('t') ->setFirstResult($args->getOffset()) ->setMaxResults($args->getLimit()); $proxyQb = $this->pqbManager->wrapQueryBuilder($qb); $qb = $proxyQb->getSortedAndFilteredQueryBuilder($args->getSearchBy(), $args->getSortBy()); $query = $qb->getQuery(); $paginator = new Paginator($query); return new QueryResult($paginator->getIterator()->getArrayCopy(), count($paginator)); } }
项目配置
<?php namespace App\QueryFilter\Config; use Artprima\QueryFilterBundle\QueryFilter\Config\BaseConfig; class ItemConfig extends BaseConfig { public function __construct() { $this->setSearchAllowedCols([ 't.name', ]); $this->setSortCols( ['t.id'], ['t.id' => 'desc'] // default ); } }
简单的查询过滤示例
注意:假设所有使用的字段都在配置中已启用
- 执行
t.name LIKE
%doe% 比较 - 执行
t.name = "Doe"
比较 - 执行
t.name <> "Doe"
比较 - 执行
t.name LIKE "Doe"
比较 - 执行
t.name NOT LIKE "Doe"
比较 - 执行
t.frequency BETWEEN 8 AND 10
比较 - 执行
t.frequency NOT BETWEEN 8 AND 10
比较 - 执行
t.frequency > 7
比较 - 执行
t.frequency >= 7
比较 - 执行
t.frequency IN (1, 2, 3, 4, 5)
比较 - 执行
t.frequency NOT IN (1, 2, 3, 4, 5)
比较 - 执行
t.description IS NULL
比较 - 执行
t.description IS NOT NULL
比较 - 执行
t.frequency < 7
比较 - 执行
t.frequency <= 7
比较 - 组合比较
t.frequency < 7 AND t.monetary > 50
高级查询过滤示例
简单模式对于大多数情况已经足够,然而有时我们可能需要构建更复杂的过滤,其中使用了相同的字段。
- 执行
t.frequency = 10 OR t.frequency >= 85
(注意:filter[1][connector]=or
-connector
可以是and
(默认)或or
;第一个过滤器上使用的连接器没有效果)
分页示例
- 第二页(注意:如果未提供
page
,则默认为 1) - 限制记录数至 100(注意:如果提供了默认限制且
limit
不在允许的值范围内,则将重置为默认值)
排序示例
- 执行
ORDER BY t.userId DESC
(如果未提供sortdir
,则默认为asc
)
注意:目前此包不支持为 ORDER BY
使用多个字段。
本文档尚未完成,后续将提供更多示例.
代码许可
您可以在 MIT 许可证的条款下自由使用本存储库中的代码。LICENSE 文件包含此许可证的副本。