在单个查询中过滤多个字段的查询

Sne*_*nek 2 php symfony graphql api-platform.com

我的设置是 Symfony 5,最新的 API-Platform 版本在 PHP 7.3 上运行。所以我希望能够查询姓名和用户名(甚至可能是电子邮件)。我需要编写自定义解析器吗?

这是我到目前为止所尝试的,但这导致 WHERE name = $name AND username = $name。

query SearchUsers ($name: String!) {
  users(name: $name, username: $name) {
    edges {
       cursor
       node {
         id
         username
         email
         avatar
       }
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

我的实体:

/**
 * @ApiResource
 * @ApiFilter(SearchFilter::class, properties={
 *   "name": "ipartial",
 *   "username": "ipartial",
 *   "email": "ipartial",
 * })
 *
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="Domain\Repository\UserRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class User
{
  private $name;
  private $username;
  private $email;
  // ... code omitted ...
}
Run Code Online (Sandbox Code Playgroud)

Met*_*ass 5

我 为教程的第 6 章制作了这样一个自定义过滤器。我在下面包含了它的代码。

您可以配置它在 ApiFilter 标签中搜索的属性。在你的情况下,这将是:

 * @ApiFilter(SimpleSearchFilter::class, properties={"name", "username", "email"})
Run Code Online (Sandbox Code Playgroud)

它将搜索字符串拆分为单词并搜索每个单词的每个属性不区分大小写,因此查询字符串如下:

?simplesearch=Katch sQuash
Run Code Online (Sandbox Code Playgroud)

将在所有指定的属性中搜索 LOWER(..) LIKE '%katch%' OR LOWER(..) LIKE '%squash%'

限制:它可能仅限于字符串属性(取决于数据库),并且不按相关性排序。

编码:

// api/src/Filter/SimpleSearchFilter.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',
                ]
            ]
        ];
    }

}
Run Code Online (Sandbox Code Playgroud)

服务需要在 api/config/services.yaml 中配置

'App\Filter\SimpleSearchFilter':
    arguments:
        $searchParameterName: 'ignoored'
Run Code Online (Sandbox Code Playgroud)

($searchParameterName 实际上可以从@ApiFilter 注解中配置)


小智 3

OR默认情况下,API 平台不处理搜索过滤器中的条件,您需要自定义过滤器来执行此操作(https://api-platform.com/docs/core/filters/#creating-custom-filters

另请参阅: https: //github.com/api-platform/core/issues/2400