API Platform 3中POST/PUT请求如何实现DTO输入与输出?
API Platform 3 写入操作同时使用不同输入输出DTO的实现方案
API Platform 3完全支持你需要的「写入操作同时使用与资源不同的输入和输出DTO」场景,你需要在资源注解中同时配置input、output,并为写入操作指定自定义State Processor和State Provider,完整流程可复现API Platform 2中DataTransformer的逻辑。
1. 资源类注解配置
在实体的ApiResource注解中,针对写入操作(如POST、PUT)同时指定输入DTO、输出DTO,以及对应的Processor和Provider:
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Get; #[ApiResource( operations: [ new Post( input: InputDto::class, output: OutputDto::class, processor: EntityWriteProcessor::class, provider: EntityReadProvider::class ), new Put( input: InputDto::class, output: OutputDto::class, processor: EntityWriteProcessor::class, provider: EntityReadProvider::class ), new Get( output: OutputDto::class, provider: EntityReadProvider::class ) ] )] class YourEntity { // 实体字段定义 }
2. 自定义State Processor(处理输入DTO转实体)
Processor负责接收输入DTO,将其转换为实体,执行业务逻辑(如持久化)后返回实体,供后续Provider转换为输出DTO:
use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use Doctrine\ORM\EntityManagerInterface; class EntityWriteProcessor implements ProcessorInterface { public function __construct(private readonly EntityManagerInterface $entityManager) {} public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): YourEntity { // 1. 输入DTO转实体 $entity = new YourEntity(); $entity->setTitle($data->getTitle()); $entity->setContent($data->getContent()); // 其他字段映射逻辑 // 2. 执行实体处理(持久化等) $this->entityManager->persist($entity); $this->entityManager->flush(); // 3. 返回实体,交由Provider转换为输出DTO return $entity; } }
3. 自定义State Provider(处理实体转输出DTO)
Provider负责接收Processor返回的实体(或从数据库查询实体),将其转换为输出DTO并返回:
use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProviderInterface; use Doctrine\ORM\EntityManagerInterface; class EntityReadProvider implements ProviderInterface { public function __construct(private readonly EntityManagerInterface $entityManager) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): OutputDto { // 获取目标实体:写入操作中可通过$context['data']获取Processor返回的实体,GET操作通过ID查询 $entity = $context['data'] ?? $this->entityManager->getRepository(YourEntity::class)->find($uriVariables['id']); // 实体转输出DTO $outputDto = new OutputDto(); $outputDto->setId($entity->getId()); $outputDto->setDisplayTitle($entity->getTitle()); $outputDto->setPreviewContent(substr($entity->getContent(), 0, 100)); // 其他字段映射逻辑 return $outputDto; } }
关键注意事项
- 写入操作必须同时指定
provider,否则API Platform会直接返回Processor输出的实体,而非配置的输出DTO - 可以使用AutoMapper、MapStruct等工具简化DTO与实体之间的映射,减少手动赋值代码
- 若需要处理集合类型的输出(如GET列表),需在Provider中添加集合转换逻辑
内容的提问来源于stack exchange,提问作者Dave Small
相关产品推荐
相关产品推荐

