API 平台:具有嵌套实体的组仅在删除 @ApiResource 时有效

API Platform : Groups with nested entities work only when removing @ApiResource

API 平台默认使用 IRI 获取嵌套实体,但我正在尝试获取使用 normalization_context 和组规范化的实体。它有效,但只有当我从嵌套实体中删除 @ApiResource 并且我需要它来公开我的 CRUD 服务时。

例子

/**
 * @ApiResource(
 *       attributes={
 *     "normalization_context"={"groups"={"goals-read"}},
 *     "denormalization_context"={"groups"={"goals-read"}}
 * })
 *
 * )
 *
 * Goals
 * @ApiFilter(OrderFilter::class, properties={"id"}, arguments={"orderParameterName"="order"})
 * @ORM\Table(name="goals", indexes={@ORM\Index(name="IDX_C7241E2FA55629DC", columns={"processus_id"})})
 * @ORM\Entity
 */
class Goals
{
    /**
     * @var int
     * @Groups("goals-read")
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

// some fields ...

    /**
     * @var Processus
     * @ORM\ManyToOne(targetEntity="Processus")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="processus_id", referencedColumnName="id")
     * })
     * @Groups({"goals-read"})
     * @ApiProperty(readableLink=false, writableLink=false)
     */
    private $processus;

    /**
     * @var Issues
     * @ORM\ManyToOne(targetEntity="Issues")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="issues_id", referencedColumnName="id")
     * })
     * @Groups({"goals-read"})
     * @ApiProperty(readableLink=false, writableLink=false)
     */
    private $issue;

进程Class

/**
 * Processus
 * @ApiResource()
 * @ORM\Table(name="processus", indexes={@ORM\Index(name="IDX_EEEA8C1DC35E566A", columns={"family_id"})})
 * @ORM\Entity
 */
class Processus
{
    /**
     * @var int
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @Groups({"goals-read"})
     */
    private $id;

    /**
     * @var string|null
     * @ORM\Column(name="name", type="string", length=255, nullable=true)
     * @Groups({"goals-read"})
     */
    private $name;

响应正文

{
  "@context": "/api/contexts/Goals",
  "@id": "/api/goals",
  "@type": "hydra:Collection",
  "hydra:member": [
    {
      "@id": "/api/goals/29",
      "@type": "Goals",
      "id": 29,
      "description": "string",
      "comment": "string",
      "currentState": "string",
      "goalToReach": "string",
      "advancement": "string",
      "indicator": 0,
      "q1": "string",
      "q2": "string",
      "q3": "string",
      "q4": "string",
      "nextYear": "string",
      "nextTwoYear": "string",
      "processus": "/api/processuses/2",
      "issue": "/api/issues/5"
}

删除@ApiResource()时

// JSON 响应

...
...
...
 "processus": {
        "@type": "Processus",
        "@id": "_:938",
        "id": 2,
        "name": "string"
      }

问题是你在 class 目标中使用了错误的结构:

* @ORM\JoinColumns({
*   @ORM\JoinColumn(name="processus_id", referencedColumnName="id")
* })

注解@JoinColumns只能用于@ManyToMany关系,在@JoinTable[=29里面=]注解.

你可以看看on related Doctrine documentation

因此,在您的情况下,您必须使用:

/**
 * @var Processus
 *
 * @ORM\ManyToOne(targetEntity="Processus")
 * @ORM\JoinColumn(name="processus_id", referencedColumnName="id")
 *
 * @Groups({"goals-read", "goals-write"})
 */
private $processus;

是的,我为非规范化上下文添加了不同的序列化组 goals-write,正如@Jeroen van der Laan 在他的评论中向您建议的那样。

希望能帮到你

原来解决方案就在我们眼皮底下,@ApiProperty(readableLink=false, writableLink=false) 注释是罪魁祸首。 The documentation regarding this annotation 明确指出这会强制将引用的实体序列化为 IRI(否决序列化组)。从 Goals::$processus 属性 中删除此注释将使 API 平台使用 goals-write 序列化组来序列化引用的 Processus 实体。

这是一个在 PHP 8 和 API 平台 2.6 中编写的工作示例(因为这是我在编写本文时目前部署的,但不要认为这里的版本是相关的):

目标

<?php declare(strict_types = 1);

//..

/**
 * @ORM\Entity
 */
#[ApiResource(
    normalizationContext: [
        'groups' => [
            'goals-read'
        ]
    ],
)]
#[ApiFilter(
    OrderFilter::class,
    properties: ['id'],
    arguments: [
        'orderParameterName' => 'order'
    ]
)]
class Goals
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(
     *      strategy="IDENTITY"
     * )
     * @ORM\Column(
     *      type="integer",
     *      nullable=false
     * )
     * @Groups({
     *      "goals-read"
     * })
     */
    private ?int $id = null;

    /**
     * @ORM\ManyToOne(
     *      targetEntity="Processus"
     * )
     * @ORM\JoinColumn(
     *      name="processus_id",
     *      referencedColumnName="id"
     * )
     * @Groups({
     *      "goals-read"
     * })
     * NO MORE @ApiProperty ANNOTATION HERE
     */
    private ?Processus $processus = null;
}

Processus

<?php declare(strict_types = 1);

//..

/**
 * @ORM\Entity
 */
#[ApiResource]
class Processus
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(
     *      strategy="IDENTITY"
     * )
     * @ORM\Column(
     *      type="integer",
     *      nullable=false
     * )
     * @Groups({
     *      "goals-read"
     * })
     */
    private ?int $id = null;

    /**
     * @ORM\Column(
     *      name="name",
     *      type="string",
     *      length=255,
     *      nullable=true
     * )
     * @Groups({
     *     "goals-read"
     * })
     */
    private ?string $name = null;
}