Api-Platform中如何从路径获取{id},避免Messenger输入重复提交ID
How to Avoid Repeating ID in Request Body (Use URL Path ID Instead) in API Platform with Messenger
当然可以解决这个重复传ID的问题!API Platform和Symfony的生态提供了很优雅的方式,让你直接从URL路径里取ID填充到CancelFooCommand里,不用在请求体里重复提交。下面是最实用的实现方案:
核心思路
我们需要一个数据转换器,它能拦截API Platform的请求处理流程:
- 从URL路径中提取
id参数 - 从请求体中获取其他参数(比如你的
note) - 把这些数据组合成完整的
CancelFooCommand对象,传递给Messenger
步骤1:创建数据转换器类
这个类负责把请求数据(路径+请求体)转换成你的Command对象:
// src/DataTransformer/CancelFooCommandDataTransformer.php namespace App\DataTransformer; use App\Command\CancelFooCommand; use ApiPlatform\Core\DataTransformer\DataTransformerInterface; final class CancelFooCommandDataTransformer implements DataTransformerInterface { public function transform($object, string $to, array $context = []): CancelFooCommand { $command = new CancelFooCommand(); // 从API Platform上下文的请求属性中获取URL里的id $command->id = $context['request_attributes']['id']; // 从请求体中获取note字段(如果存在的话) $command->note = $object['note'] ?? ''; return $command; } public function supportsTransformation($data, string $to, array $context = []): bool { // 指定这个转换器只处理CancelFooCommand,且仅针对put_cancel操作 return CancelFooCommand::class === $to && isset($context['item_operation_name']) && 'put_cancel' === $context['item_operation_name']; } }
步骤2:修改CancelFooCommand的配置
移除id字段上的identifier=true标记,告诉API Platform这个字段不需要从请求体获取:
// src/Command/CancelFooCommand.php final class CancelFooCommand { /** * @var string */ public string $id = ''; /** * @var string * @ApiProperty( * attributes={ * "openapi_context": { * "type": "string" * } * } * ) */ public string $note = ''; }
步骤3:验证效果
现在你发送PUT请求到/task/{id}/cancel时,只需要在请求体里传note字段即可:
{ "note": "取消任务的原因" }
数据转换器会自动把URL里的id填充到CancelFooCommand的id属性中,Messenger Handler收到的就是完整的Command对象了。
额外说明
如果你更习惯用Symfony的RequestStack来获取请求参数,也可以修改转换器的构造函数:
use Symfony\Component\HttpFoundation\RequestStack; final class CancelFooCommandDataTransformer implements DataTransformerInterface { public function __construct(private RequestStack $requestStack) {} public function transform($object, string $to, array $context = []): CancelFooCommand { $command = new CancelFooCommand(); $command->id = $this->requestStack->getCurrentRequest()->get('id'); $command->note = $object['note'] ?? ''; return $command; } // supportsTransformation方法不变 }
两种方式都能正常工作,用API Platform上下文的方式更贴合其扩展机制,而RequestStack则更通用,适合需要更多请求信息的场景。
内容的提问来源于stack exchange,提问作者Nolifer
相关产品推荐
相关产品推荐

