有没有办法使用 DTO 将过滤器添加到自定义端点?
Is there a way to add filters to custom endpoint with DTO?
我有一个自定义端点(它执行一些自定义聚合),此端点的 return 是 DTO 的集合。我想为 api 的消费者添加一些过滤器建议。这可能吗 ?你怎么能那样做?
总结一下:
- 我有一个 DTO(ApiResource 但没有链接到学说或数据库)。
- 我有一个自定义 GET 端点,它 return DTO 的集合(过滤或不过滤)。
- 我想向此端点添加过滤器建议。
我应该以某种方式修改 hydra:search 吗?
我试图在我的 DTO 上添加 ApiFilters(就像我为实体所做的那样),但是 ApiFilters 链接到学说所以它给了我以下错误:Call to a member function getClassMetadata() on null
on vendor/api-platform/core/src/Bridge/Doctrine/Common/PropertyHelperTrait.php
我遇到了同样的问题,为了解决这个问题,我创建了一个没有 $this->isPropertyMapped
部分的自定义过滤器。
我将 ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\FilterExtension
注入到我的收集提供者并应用我的过滤器
$this->filterExtension->applyToCollection($qb, $queryNameGenerator, $resourceClass, $operationName, $context);
为了改变查询。
然后我只需要在我的 dto 对象中配置我的自定义过滤器
@ApiFilter(SearchFilter::class, properties={"columnName": "exact"})
<?php
declare(strict_types=1);
namespace App\ThirdParty\ApiPlatform\Filter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
final class SearchFilter extends AbstractContextAwareFilter
{
protected function filterProperty(
string $property,
$value,
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
string $operationName = null
): void {
if (
!$this->isPropertyEnabled($property, $resourceClass)
) {
return;
}
$parameterName = $queryNameGenerator->generateParameterName($property);
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder
->andWhere(sprintf('%s.%s = :%s', $rootAlias, $property, $parameterName))
->setParameter($parameterName, $value);
}
public function getDescription(string $resourceClass): array
{
if (!$this->properties) {
return [];
}
$description = [];
foreach ($this->properties as $property => $strategy) {
$description["regexp_$property"] = [
'property' => $property,
'type' => 'string',
'required' => false,
'swagger' => [
'description' => 'description',
'name' => $property,
'type' => 'type',
],
];
}
return $description;
}
}
我有一个自定义端点(它执行一些自定义聚合),此端点的 return 是 DTO 的集合。我想为 api 的消费者添加一些过滤器建议。这可能吗 ?你怎么能那样做?
总结一下:
- 我有一个 DTO(ApiResource 但没有链接到学说或数据库)。
- 我有一个自定义 GET 端点,它 return DTO 的集合(过滤或不过滤)。
- 我想向此端点添加过滤器建议。
我应该以某种方式修改 hydra:search 吗?
我试图在我的 DTO 上添加 ApiFilters(就像我为实体所做的那样),但是 ApiFilters 链接到学说所以它给了我以下错误:Call to a member function getClassMetadata() on null
on vendor/api-platform/core/src/Bridge/Doctrine/Common/PropertyHelperTrait.php
我遇到了同样的问题,为了解决这个问题,我创建了一个没有 $this->isPropertyMapped
部分的自定义过滤器。
我将 ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\FilterExtension
注入到我的收集提供者并应用我的过滤器
$this->filterExtension->applyToCollection($qb, $queryNameGenerator, $resourceClass, $operationName, $context);
为了改变查询。
然后我只需要在我的 dto 对象中配置我的自定义过滤器
@ApiFilter(SearchFilter::class, properties={"columnName": "exact"})
<?php
declare(strict_types=1);
namespace App\ThirdParty\ApiPlatform\Filter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
final class SearchFilter extends AbstractContextAwareFilter
{
protected function filterProperty(
string $property,
$value,
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
string $operationName = null
): void {
if (
!$this->isPropertyEnabled($property, $resourceClass)
) {
return;
}
$parameterName = $queryNameGenerator->generateParameterName($property);
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder
->andWhere(sprintf('%s.%s = :%s', $rootAlias, $property, $parameterName))
->setParameter($parameterName, $value);
}
public function getDescription(string $resourceClass): array
{
if (!$this->properties) {
return [];
}
$description = [];
foreach ($this->properties as $property => $strategy) {
$description["regexp_$property"] = [
'property' => $property,
'type' => 'string',
'required' => false,
'swagger' => [
'description' => 'description',
'name' => $property,
'type' => 'type',
],
];
}
return $description;
}
}