You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:12:36