首页 > 解决方案 > 如何在 Api-Platform 中为虚拟属性引入过滤功能?

问题描述

我正在使用 Symfony 5 和 API 平台。

我的一个类有一个通过postLoad监听器设置的属性。该属性仅在某些条件下设置(否则为NULL),我希望允许 REST API 用户根据此属性是否为 null 或具有值来过滤资源。

因为虚拟属性没有持久化到数据库中,我假设没有任何 Doctrine 过滤器,例如ExistsFilter,将在这个属性上工作。

如何使用 Symfony 5 和 API 平台为虚拟属性创建过滤功能?

标签: phpsymfonyapi-platform.comsymfony5

解决方案


您可以创建自己的自定义 ORM 过滤器

一个非常简单的例子来展示它是如何完成的:

假设一个类:

Foo {

    public int $weight;

    public function isHeavy(): bool {
        return $this->weight > 40;
    }
}

由于heavy是“虚拟”属性,因此您无法直接对其进行过滤。

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;

class HeavyFilter extends AbstractContextAwareFilter
{
    public function getDescription(string $resourceClass): array
    {
        // I'm making the filter available only 
        if (Foo::class !== $resourceClass) {
            return [];
        }

        
        if (!$this->properties) {
            return [];
        }

        $description                      = [];
        $description['heavySearch']   =
            [
                'property' => 'heavy',
                'type'     => 'bool',
                'required' => false,
                'swagger'  => [
                    'description' => 'Search for heavy foos',
                    'name'        => 'Heavey Search',
                    'type'        => 'bool',
                ],
            ];

        return $description;
    }

    protected function filterProperty(
        string $property,
        $value,
        QueryBuilder $queryBuilder,
        QueryNameGeneratorInterface $queryNameGenerator,
        string $resourceClass,
        string $operationName = null
    ): void {
        if ('heavySearch' !== $property) {
            return;
        }

        if ($value === true) {
            $queryBuilder
                ->andWhere('o.weigth > 40');
        }
        else {
            $queryBuilder
                ->andWhere('o.weight <= 40');
        }
    }
}

还没有实际测试过这个,只是在这里写的,但基本想法是正确的。您需要根据自己的情况进行调整,并且您将拥有一个自定义过滤器,它甚至可以在 Open Api 文档中找到。


推荐阅读