将子资源映射到不使用 ApiPlatform >= 2.7

问题描述 投票:0回答:0

在我们使用 ApiPlatform 的应用程序中,我们将数据库实体映射到 DTO。对于高达 v2.6.8 的版本,这不仅适用于所请求的根实体,而且适用于嵌套关系。它们每个都在

output
属性中拥有一个
ApiResource
设置,并且它们通过 DataTransformers 进行映射。

当通过

/api/products
访问产品列表时,我可以看到所有正在使用的转换器,不仅是根实体,还有相关实体。

基于 ApiPlatform v2.6 的示例代码:

#[ApiResource(
    collectionOperations: ['get'],
    itemOperations: ['get'],
    normalizationContext: ['groups' => ['product_read', 'vehicle_read']],
    output: ProductOutput::class
)]
class Product
{
    #[ORM\Id]
    #[ORM\Column(type: 'product_id')]
    private int $id;

    #[ORM\Column(type: Types::STRING)]
    private string $name = '';

    #[ORM\ManyToOne(targetEntity: Vehicle::class, inversedBy: 'products', cascade: ['persist'])]
    #[ORM\JoinColumn(name: 'vehicle_id', referencedColumnName: 'id', nullable: false)]
    private ?Vehicle $vehicle = null;
}

class ProductOutput
{
    #[Groups(['product_read'])]
    private readonly int $id;

    #[Groups(['product_read'])]
    private readonly string $name;

    #[Groups(['product_read'])]
    private readonly Vehicle $vehicle;

    public function __construct(Product $product)
    {
        $this->id = $product->getId()->value();
        $this->name = $product->getName();
        $this->vehicle = $product->getVehicle();
    }

    public function getVehicle(): Vehicle
    {
        return $this->vehicle;
    }
}

class ProductDataTransformer implements DataTransformerInterface
{
    /**
     * @param Product|object $object
     */
    public function transform($object, string $to, array $context = []): ProductOutput
    {
        if (!$object instanceof Product) {
            throw new InvalidArgumentException($object, Product::class);
        }
        
        return new ProductOutput($object);
    }

    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        return ProductOutput::class === $to && $data instanceof Product;
    }
}

#[ApiResource(
    collectionOperations: ['get'],
    itemOperations: ['get'],
    normalizationContext: ['groups' => ['vehicle_read']],
    output: VehicleOutput::class,
)]
class Vehicle
{
    #[ORM\Id]
    #[ORM\Column(type: 'vehicle_id')]
    private int $id;

    #[ORM\Column(type: 'string')]
    private string $brand;

    public function __construct(
        int $vehicleId,
        string $brand
    ) {
        $this->id = $vehicleId;
        $this->brand = $brand;
    }
}

class VehicleOutput
{
    #[Groups('vehicle_read')]
    private readonly int $id;

    #[Groups('vehicle_read')]
    private readonly string $brand;

    public function __construct(Vehicle $vehicle)
    {
        $this->id = $vehicle->getId();
        $this->brand = $vehicle->getBrand();
    }
}

class VehicleDataTransformer implements DataTransformerInterface
{
    /**
     * @param Vehicle|object $object
     */
    public function transform($object, string $to, array $context = []): VehicleOutput
    {
        if (!$object instanceof Vehicle) {
            throw new InvalidArgumentException($object, Vehicle::class);
        }

        return new VehicleOutput($object);
    }

    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        return VehicleOutput::class === $to && $data instanceof Vehicle;
    }
}

升级到 ApiPlatform v2.7 甚至 v3.0 后,使用相同的概念将不起作用。嵌套实体的转换器不会被触发,应该用于 v3 的状态处理器也不会被触发。序列化过程没有考虑到嵌套实体应该以任何特殊格式进行转换,而且我找不到任何关于如何执行此操作的适当文档。

将所有相关实体的配置放入主 DTO 中是可能的,但这会使所有映射不可重用,并且在要更改车辆映射时更改产品的 DTO 是我想避免的事情。

与 v3 中的状态处理器相同:它们只为根实体触发,不考虑嵌套实体。


有没有人以前做过这样的设置,可以分享有关如何正确配置映射的见解?

php symfony api-platform.com
© www.soinside.com 2019 - 2024. All rights reserved.