symfony - 如何使用 Api-Platform 集成 SearchFilter 以在实体的多个属性中进行搜索?
问题描述
我在表ID中有 4 个字段| 姓名 | EAN | 韩
这些是我的一个实体中的属性所以,我如何使用 searchFilter 配置实体,以便当我搜索一个字符串时,它应该在所有 4 列中检查它并返回匹配的结果。
例如:-如果我搜索“car”,它将在 name 属性中匹配并返回,但是当我输入 id 说“219”时,它将在 id 属性中匹配并相应地返回给我。
我只想使用 api-platform 来实现这一点,我的项目在 symfony 中。
因此,搜索应该查看所有 4 个字段,然后返回结果。
解决方案
您可以使用将这些条件与 OR 相结合的自定义过滤器来归档它。我为教程的第 6 章排序和自定义过滤器做了一个。我在下面包含了它的代码。
您可以配置它在 ApiFilter 标记中搜索的属性。在你的情况下,这将是:
* @ApiFilter(SimpleSearchFilter::class, properties={"ID", "Name", "EAN", "HAN"})
一个查询字符串,如:
?simplesearch=car
将搜索所有指定不区分大小写的属性 LIKE %car% (如果您以编程方式创建查询字符串,则需要对参数值进行 url 编码)
您还可以在 ApiFilter 标签中配置参数名称。例如:
* @ApiFilter(SimpleSearchFilter::class, properties={"ID", "Name", "EAN", "HAN"}, arguments={"searchParameterName"="search"})
将允许查询字符串,如:
?search=car
我必须决定这个过滤器如何与其他过滤器结合。为了与现有的过滤器兼容,我使用了 AND。因此,例如,如果您还将标准 DateFilter 添加到同一实体类,您将能够在指定字段中搜索某些单词,并且在指定日期之后但不能在指定日期之后搜索。例如:
?simplesearch=car&produced[after]=2018-03-31
它将搜索字符串拆分为单词并搜索每个单词的每个属性,因此
?simplesearch=car 219
将在所有指定的属性中搜索 .. LIKE %car% 或 .. LIKE %219%
是的,它确实假设所有属性都是字符串类型,或者您的数据库支持 LIKE 其他属性类型(MySQL 支持,Postgres 不支持,因此如果 ID 是 int,这将不适用于 Postgres)。该过滤器也不支持嵌套属性,也不按相关性排序(这就是它被称为 SimpleSearchFilter 的原因)。
当然你可以随意更改代码,如果你知道如何使用 Doctrine 中的元数据,为其他数据类型的属性添加不同的处理不会太难。如您在 api/vendor/api-platform/core/src/Bridge/Doctrine/Orm/Filter/SearchFilter.php 的代码及其使用的特征中所见,添加嵌套属性将非常困难。因此将按相关性排序。
这是代码:
<?php
namespace App\Filter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
/**
* Selects entities where each search term is found somewhere
* in at least one of the specified properties.
* Search terms must be separated by spaces.
* Search is case insensitive.
* All specified properties type must be string.
* @package App\Filter
*/
class SimpleSearchFilter extends AbstractContextAwareFilter
{
private $searchParameterName;
/**
* Add configuration parameter
* {@inheritdoc}
* @param string $searchParameterName The parameter whose value this filter searches for
*/
public function __construct(ManagerRegistry $managerRegistry, ?RequestStack $requestStack = null, LoggerInterface $logger = null, array $properties = null, NameConverterInterface $nameConverter = null, string $searchParameterName = 'simplesearch')
{
parent::__construct($managerRegistry, $requestStack, $logger, $properties, $nameConverter);
$this->searchParameterName = $searchParameterName;
}
/** {@inheritdoc} */
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null, array $context = [])
{
if (null === $value || $property !== $this->searchParameterName) {
return;
}
$words = explode(' ', $value);
foreach ($words as $word) {
if (empty($word)) continue;
$this->addWhere($queryBuilder, $word, $queryNameGenerator->generateParameterName($property));
}
}
private function addWhere($queryBuilder, $word, $parameterName)
{
$alias = $queryBuilder->getRootAliases()[0];
// Build OR expression
$orExp = $queryBuilder->expr()->orX();
foreach ($this->getProperties() as $prop => $ignoored) {
$orExp->add($queryBuilder->expr()->like('LOWER('. $alias. '.' . $prop. ')', ':' . $parameterName));
}
$queryBuilder
->andWhere('(' . $orExp . ')')
->setParameter($parameterName, '%' . strtolower($word). '%');
}
/** {@inheritdoc} */
public function getDescription(string $resourceClass): array
{
$props = $this->getProperties();
if (null===$props) {
throw new InvalidArgumentException('Properties must be specified');
}
return [
$this->searchParameterName => [
'property' => implode(', ', array_keys($props)),
'type' => 'string',
'required' => false,
'swagger' => [
'description' => 'Selects entities where each search term is found somewhere in at least one of the specified properties',
]
]
];
}
}
由于构造函数参数“searchParameterName”,服务需要在 api/config/services.yaml 中配置
'App\Filter\SimpleSearchFilter':
arguments:
$searchParameterName: 'ignoored'
推荐阅读
- docker - 如何解决 EACCES:权限被拒绝,mkdir 'build/..' - Docker + Ubuntu
- php - 在 docker 容器中使用 php-fpm 的 Nginx 不会登录 php 错误
- image - 无法提取或转换 SWF 文件,因为它们似乎已损坏
- mysql - 选择 MySQL 列的默认值
- arm - 如何设置 stm32f4 实时时钟(RTC)以在亚秒寄存器中获取有效值?
- python - 将自定义格式的文本打印到 cmd 控制台
- oauth - 使用 OAuth2 自定义提供程序登录 GitLab 不会映射用户信息
- mysql - 如何获得大表的计数?
- python - 如何选择列并为不存在的列生成 Nan 值?
- vba - 如何在 Access 中将表单跳转到特定记录?