在我们使用 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 中的状态处理器相同:它们只为根实体触发,不考虑嵌套实体。
有没有人以前做过这样的设置,可以分享有关如何正确配置映射的见解?