API Platform无法将Goal注入独立Api Resource/DTO问题排查
问题描述
创建了独立的Api Resource,但系统无法将Goal注入到GoalShareAction类中,尝试单独DTO也遇到同样问题。User能正常注入,已尝试调整provider、read/write属性等配置。
请求路径:http://localhost/goals/6/share
请求体:
{"user": "/api/users/1"}
对应代码:
#[ApiResource( operations: [ new Post( uriTemplate: '/goals/{id}/share', status: 201, processor: GoalShareProcessor::class, ), ], normalizationContext: ['groups' => ['share:read', 'share:write']], denormalizationContext: ['groups' => ['share:read', 'share:write']], )] final class GoalShareAction { #[Groups(['share:write', 'share:read'])] #[ApiProperty(identifier: true)] public Goal $goal; #[Groups(['share:write', 'share:read'])] public User $user; }
输出结果:
App\ApiResource\Goal\GoalShareAction {#13214 +goal: ? App\Entity\Goal +user:App\Entity\User {#17574 #id: 12
解决方案
问题核心是URI模板中的{id}参数没有和GoalShareAction的goal属性关联。API Platform默认不会自动将路径参数映射到DTO/Resource类的属性,而User能正常注入是因为请求体里的user是IRI格式,系统会自动解析加载实体。
方法一:用MapEntity注解(API Platform 3.x及以上)
在goal属性上添加#[MapEntity]注解,明确将URI参数id映射到Goal实体:
use ApiPlatform\Metadata\MapEntity; #[ApiResource( operations: [ new Post( uriTemplate: '/goals/{id}/share', status: 201, processor: GoalShareProcessor::class, ), ], normalizationContext: ['groups' => ['share:read', 'share:write']], denormalizationContext: ['groups' => ['share:read', 'share:write']], )] final class GoalShareAction { #[Groups(['share:write', 'share:read'])] #[ApiProperty(identifier: true)] #[MapEntity(id: 'id')] // 关联URI的id参数到Goal实体 public Goal $goal; #[Groups(['share:write', 'share:read'])] public User $user; }
方法二:自定义Provider
如果不想用注解,可创建Provider类手动加载Goal并注入到GoalShareAction:
// 先创建Provider类 namespace App\State\Provider; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProviderInterface; use App\ApiResource\Goal\GoalShareAction; use App\Entity\Goal; use Doctrine\ORM\EntityManagerInterface; class GoalShareProvider implements ProviderInterface { public function __construct(private EntityManagerInterface $em) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { $goal = $this->em->getRepository(Goal::class)->find($uriVariables['id']); $action = new GoalShareAction(); $action->goal = $goal; return $action; } } // 然后在ApiResource的Post操作中指定provider #[ApiResource( operations: [ new Post( uriTemplate: '/goals/{id}/share', status: 201, processor: GoalShareProcessor::class, provider: \App\State\Provider\GoalShareProvider::class, // 指定自定义Provider ), ], normalizationContext: ['groups' => ['share:read', 'share:write']], denormalizationContext: ['groups' => ['share:read', 'share:write']], )] final class GoalShareAction { #[Groups(['share:write', 'share:read'])] #[ApiProperty(identifier: true)] public Goal $goal; #[Groups(['share:write', 'share:read'])] public User $user; }
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

