API 平台:具有嵌套实体的组仅在删除 @ApiResource 时有效
Posted
技术标签:
【中文标题】API 平台:具有嵌套实体的组仅在删除 @ApiResource 时有效【英文标题】:API Platform : Groups with nested entities work only when removing @ApiResource 【发布时间】:2021-06-19 10:56:34 【问题描述】: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;
进程类
/**
* 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"
【问题讨论】:
考虑从denormalization_context
组中删除goals-read
,因为非规范化组用于指定传入有效负载,而不是传出有效负载。您是否尝试在不使用 attribute
属性的情况下使用配置上下文?例如@ApiResource(normalizationContext="groups"="goals-read")
。或者通过在collectionOperations
GET操作下配置normalization_context
来代替?
【参考方案1】:
问题是你在目标类中使用了错误的结构:
* @ORM\JoinColumns(
* @ORM\JoinColumn(name="processus_id", referencedColumnName="id")
* )
注解@JoinColumns只能用于@ManyToMany关系,在@JoinTable注解内。
你可以看看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 在他的评论中向您建议的那样。
希望我能帮到你。
【讨论】:
您好@Alexander Yakutskiy,注释@JoinColumns 是在使用make: entity
命令时自动生成的。但是我尝试了您的解决方案,但问题仍然存在,还尝试了@Jeroen van der Laan 提到的所有组合。欲了解更多信息:我正在使用:api-platform 2.6.3 php 7.4.15 Symfony 5.2.3【参考方案2】:
原来解决方案就在我们的眼皮底下,@ApiProperty(readableLink=false, writableLink=false)
注释是罪魁祸首。 The documentation regarding this annotation 明确指出,这会强制将引用的实体序列化为 IRI(否决序列化组)。从Goals::$processus
属性中删除此注释将使API 平台使用goals-write
序列化组来序列化引用的Processus
实体。
这是一个用 PHP 8 和 API Platform 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;
流程
<?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;
【讨论】:
以上是关于API 平台:具有嵌套实体的组仅在删除 @ApiResource 时有效的主要内容,如果未能解决你的问题,请参考以下文章
仅在父子实体具有 1 到 M 关系的核心数据中获取父实体的数据