#json #symfony #normalization #api-platform.com #symfony5
Вопрос:
Платформа 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"})
* @ORMTable(name="goals", indexes={@ORMIndex(name="IDX_C7241E2FA55629DC", columns={"processus_id"})})
* @ORMEntity
*/
class Goals
{
/**
* @var int
* @Groups("goals-read")
* @ORMColumn(name="id", type="integer", nullable=false)
* @ORMId
* @ORMGeneratedValue(strategy="IDENTITY")
*/
private $id;
// some fields ...
/**
* @var Processus
* @ORMManyToOne(targetEntity="Processus")
* @ORMJoinColumns({
* @ORMJoinColumn(name="processus_id", referencedColumnName="id")
* })
* @Groups({"goals-read"})
* @ApiProperty(readableLink=false, writableLink=false)
*/
private $processus;
/**
* @var Issues
* @ORMManyToOne(targetEntity="Issues")
* @ORMJoinColumns({
* @ORMJoinColumn(name="issues_id", referencedColumnName="id")
* })
* @Groups({"goals-read"})
* @ApiProperty(readableLink=false, writableLink=false)
*/
private $issue;
Класс Processus
/**
* Processus
* @ApiResource()
* @ORMTable(name="processus", indexes={@ORMIndex(name="IDX_EEEA8C1DC35E566A", columns={"family_id"})})
* @ORMEntity
*/
class Processus
{
/**
* @var int
* @ORMColumn(name="id", type="integer", nullable=false)
* @ORMId
* @ORMGeneratedValue(strategy="IDENTITY")
* @Groups({"goals-read"})
*/
private $id;
/**
* @var string|null
* @ORMColumn(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"
}
Комментарии:
1. Рассмотрите возможность удаления
goals-read
изdenormalization_context
групп, так как группы денормализации используются для указания входящих полезных нагрузок, а не исходящих. Вы пытались использовать настройку контекста(ов) без использованияattribute
свойства? Например@ApiResource(normalizationContext={"groups"={"goals-read"}})
. Илиnormalization_context
вместо этого настроивcollectionOperations
операцию «ПОЛУЧИТЬ»?
Ответ №1:
Оказывается, решение было прямо у нас под носом, @ApiProperty(readableLink=false, writableLink=false)
а виновником была аннотация. В документации, касающейся этой аннотации, четко указано, что это заставляет ссылаться на объекты, которые будут сериализованы как IRI (отменяющие группы сериализации). Удаление этой аннотации из Goals::$processus
свойства приведет к тому, что платформа API будет использовать группу goals-write
сериализации Processus
для сериализации объекта, на который имеется ссылка.
Вот рабочий пример, написанный на PHP 8 и платформе API 2.6 (поскольку это то, что я в настоящее время развернул при написании этого, не думаю, что версии здесь актуальны):
Цели
<?php declare(strict_types = 1);
//..
/**
* @ORMEntity
*/
#[ApiResource(
normalizationContext: [
'groups' => [
'goals-read'
]
],
)]
#[ApiFilter(
OrderFilter::class,
properties: ['id'],
arguments: [
'orderParameterName' => 'order'
]
)]
class Goals
{
/**
* @ORMId
* @ORMGeneratedValue(
* strategy="IDENTITY"
* )
* @ORMColumn(
* type="integer",
* nullable=false
* )
* @Groups({
* "goals-read"
* })
*/
private ?int $id = null;
/**
* @ORMManyToOne(
* targetEntity="Processus"
* )
* @ORMJoinColumn(
* name="processus_id",
* referencedColumnName="id"
* )
* @Groups({
* "goals-read"
* })
* NO MORE @ApiProperty ANNOTATION HERE
*/
private ?Processus $processus = null;
}
Processus
<?php declare(strict_types = 1);
//..
/**
* @ORMEntity
*/
#[ApiResource]
class Processus
{
/**
* @ORMId
* @ORMGeneratedValue(
* strategy="IDENTITY"
* )
* @ORMColumn(
* type="integer",
* nullable=false
* )
* @Groups({
* "goals-read"
* })
*/
private ?int $id = null;
/**
* @ORMColumn(
* name="name",
* type="string",
* length=255,
* nullable=true
* )
* @Groups({
* "goals-read"
* })
*/
private ?string $name = null;
}
Ответ №2:
Дело в том, что вы используете неправильную конструкцию в целях класса:
* @ORMJoinColumns({
* @ORMJoinColumn(name="processus_id", referencedColumnName="id")
* })
Аннотацию @JoinColumns можно использовать только для отношений @ManyToMany внутри аннотации @JoinTable.
Вы можете ознакомиться с соответствующей документацией по доктрине
Итак, в вашем случае вы должны использовать:
/**
* @var Processus
*
* @ORMManyToOne(targetEntity="Processus")
* @ORMJoinColumn(name="processus_id", referencedColumnName="id")
*
* @Groups({"goals-read", "goals-write"})
*/
private $processus;
И да, я добавил различные цели группы сериализации-напишите для контекста денормализации, как предложил вам @Jeroen ван дер Лаан в своем комментарии.
Надеюсь, я смогу вам помочь.
Комментарии:
1. Здравствуйте @Александр Якутский, Аннотация @JoinColumns генерируется автоматически при использовании
make: entity
команды. Но я попробовал ваше решение, и проблема все еще существует, также попробовал все комбинации, как упоминал @Jeroen ван дер Лаан. для получения дополнительной информации: я использую : api-платформу 2.6.3 php 7.4.15 Symfony 5.2.3