opwoco / query-filter-bundle
在您的Symfony 4应用中(使用Doctrine2作为ORM)轻松过滤请求的方法。
1.1.1
2019-07-24 13:42 UTC
Requires
- php: >=7.1.0
- doctrine/orm: ^2.6
Requires (Dev)
- phpunit/phpunit: ^7.0
This package is not auto-updated.
Last update: 2024-09-13 12:58:16 UTC
README
Query Filter Bundle
Query Filter Bundle将请求过滤和分页功能引入使用Doctrine 2的Symfony 4应用程序。
安装
首先,安装依赖项
$ 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->setAllowedLimits([10, 25, 50, 100]); $config->setDefaultLimit(10); $config->setSortCols(['t.id'], ['t.id' => 'asc']); $config->setRequest(new Request($request)); // 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\Mysql\PaginationWalker; use Artprima\QueryFilterBundle\Query\ConditionManager; use Artprima\QueryFilterBundle\Query\ProxyQueryBuilder; use Artprima\QueryFilterBundle\QueryFilter\QueryFilterArgs; use Artprima\QueryFilterBundle\QueryFilter\QueryResult; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; 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 = new ProxyQueryBuilder($qb, $this->pqbManager); $qb = $proxyQb->getSortedAndFilteredQueryBuilder($args->getSearchBy(), $args->getSortBy()); $query = $qb->getQuery(); $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, PaginationWalker::class); $query->setHint("mysqlWalker.sqlCalcFoundRows", true); $result = $query->getResult(); $totalRows = $this->_em->getConnection()->query('SELECT FOUND_ROWS()')->fetchColumn(); // return the wrapped result return new QueryResult($result, $totalRows); } // ... }
现在您可以启动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\Mysql\PaginationWalker; use Artprima\QueryFilterBundle\Query\ConditionManager; use Artprima\QueryFilterBundle\Query\ProxyQueryBuilder; use Artprima\QueryFilterBundle\QueryFilter\QueryFilterArgs; use Artprima\QueryFilterBundle\QueryFilter\QueryResult; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; 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 = new ProxyQueryBuilder($qb, $this->pqbManager); $qb = $proxyQb->getSortedAndFilteredQueryBuilder($args->getSearchBy(), $args->getSortBy()); $query = $qb->getQuery(); $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, PaginationWalker::class); $query->setHint("mysqlWalker.sqlCalcFoundRows", true); $result = $query->getResult(); $totalRows = $this->_em->getConnection()->query('SELECT FOUND_ROWS()')->fetchColumn(); return new QueryResult($result, $totalRows); } }
ItemConfig
<?php namespace App\QueryFilter\Config; use Artprima\QueryFilterBundle\QueryFilter\Config\BaseConfig; class ItemConfig extends BaseConfig { public function __construct() { $this->setSearchAllowedCols(array( 't.name', )); $this->setSortCols( array( 't.id', ), array('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 文件包含此许可的副本。