symfony 如何使用默认的API平台过滤器和自定义操作?

whhtz7ly  于 2023-03-03  发布在  其他
关注(0)|答案(2)|浏览(126)

我有一个自定义操作(在文档中被视为推荐方法),它生成一些逻辑并返回实体的集合。
与常规api平台的动作过滤器完美地工作。但我怎么能得到任何从默认的过滤器来工作与此集合在我的自定义动作?
当我请求GET /cars?createdAt[after]=2018-08-01GET /drivers?createdAt[after]=2018-08-01时,它按预期工作。
但是当我尝试做GET /drivers/42/cars_custom_logic?createdAt[after]=2018-08-01的时候,它没有过滤任何东西。这是我所期望的,因为我没有在我的自定义操作中调用filter,但是我的问题是-如何添加这个过滤器?

App\Entity\Car

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity
 * @ApiResource
 * @ApiFilter(DateFilter::class, properties={"createdAt"})
 */
class Car
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"car", "driver"})
     */
    private $id;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"car", "driver"})
     */
    private $createdAt;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Driver", inversedBy="cars")
     * @Groups({"car", "driver"})
     */
    private $driver;

    public function __construct()
    {
        $this->createdAt = new \DateTime('now');
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function getCreatedAt(): \DateTimeInterface
    {
        return $this->createdAt;
    }

    public function getDriver(): Driver
    {
        return $this->driver;
    }
}

一米四分一秒

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity
 * @ApiResource(itemOperations={
 *     "get",
 *     "special"={
 *         "method"="GET",
 *         "path"="/drivers/{id}/cars_custom_logic",
 *         "controller"=GetDriverCarsAction::class
 *     }
 * })
 * @ApiFilter(DateFilter::class, properties={"createdAt"})
 */
class Driver
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"car", "driver"})
     */
    private $id;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"car", "driver"})
     */
    private $createdAt;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Car", mappedBy="driver")
     * @Groups({"car", "driver"})
     */
    private $cars;

    public function __construct()
    {
        $this->createdAt = new \DateTime('now');
    }

    public function getId(): int
    {
        return $this->id;
    }
    public function getCreatedAt(): \DateTimeInterface
    {
        return $this->createdAt;
    }

    /**
     * @return Collection|Car[]
     */
    public function getCars(): Collection
    {
        return $this->cars;
    }
}

App\Controller\GetDriverCarsAction

<?php

namespace App\Controller;

use App\Entity\Car;
use App\Entity\Driver;
use Doctrine\Common\Collections\Collection;
use Symfony\Bridge\Doctrine\RegistryInterface;

final class GetDriverCarsAction
{
    private $doctrine;

    public function __construct(RegistryInterface $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function __invoke(Driver $driver): Collection
    {
        $cars = $driver->getCars();

        // ..... Some domain logic .....

        // ..... Here – what should i do to make filter work here? .....

        return $cars;
    }
}
siotufzp

siotufzp1#

如果你试着像这样通过yaml添加:

# api/config/api_platform/resources.yaml
App\Entity\Book:
    attributes:
       filters: [ offer.date_filter ]
    itemOperations:
        get: ~
        special:
            method: 'GET'
            path: '/books/{id}/special'
            controller: 'App\Controller\BookSpecial'

# api/config/api_platform/resources.yaml
App\Entity\Book:
    itemOperations:
        get: ~
        special:
            method: 'GET'
            path: '/books/{id}/special'
            controller: 'App\Controller\BookSpecial'
            filters: ['offer.date_filter']

要更深入地了解此文档:https://api-platform.com/docs/core/filters#doctrine-orm-filters
希望能有所帮助

7cjasjjr

7cjasjjr2#

    • API平台3解决方案**

我学习API平台2个星期以来,但我想我已经得到了点digging into the CollectionProvider
我需要一个自定义端点,显示购物车元数据(总数、总金额等)并能够使用筛选器(即日期筛选器)。
首先,你的自定义操作应该是一个带有状态提供器的GetCollection,或者需要实现一个扩展(空)接口CollectionOperationInterface的自定义操作类,否则你想通过OpenApiFactory的检查,而Swagger UI不会在UI中显示过滤器。我知道这感觉不对,在我的例子中,我将返回一个带有统计信息的DTO,而不是一个集合。
示例:

#[ApiResource]
#[GetCollection(
    uriTemplate: '/carts/meta',
    provider: CartGetMetaProvider::class,
    output: CartMeta::class,
)]
class Cart
{
}

现在是提供程序。提供程序应该创建一个查询生成器并注入查询扩展。ORM示例:

class CartGetMetaProvider implements ProviderInterface
{    
    public function __construct(
        private readonly ManagerRegistry $managerRegistry,
        #[TaggedIterator('api_platform.doctrine.orm.query_extension.collection')]
        private readonly iterable $collectionExtensions,
    ) {
    }

    public function provide(
        Operation $operation, 
        array $uriVariables = [], 
        array $context = []): object|array|null
    {
        $entityClass = $operation->getClass();
        if (($options = $operation->getStateOptions()) 
            && $options instanceof Options && $options->getEntityClass()) {
            $entityClass = $options->getEntityClass();
        }

        /** @var \Doctrine\Orm\EntityManagerInterface $manager */
        $manager = $this->managerRegistry->getManagerForClass($entityClass);

        $repository = $manager->getRepository($entityClass);
        if (!method_exists($repository, 'createStatsQueryBuilder')) {
            throw new RuntimeException(
                'The repository class must have a "createStatsQueryBuilder" method.'
            );
        }

        $queryBuilder = $repository->createStatsQueryBuilder('o');
        $queryNameGenerator = new QueryNameGenerator();

        foreach ($this->collectionExtensions as $extension) {
            $extension->applyToCollection(
                $queryBuilder, 
                $queryNameGenerator, 
                $entityClass, 
                $operation,
                $context
            );
        }

        // Here filters are applied, do whatever you want with the query
        // I.e. fill a custom output DTO with stats/metadata
       
   }
}

如果您需要像原始问题那样的父/子关系,请查看我链接的CollectionProvider

相关问题