Как сохранить вложенную связь с сущностью на платформе API

У меня есть две сущности, Вопрос и Альтернатива, где вопрос имеет отношение OneToMany с альтернативой, и я пытаюсь отправить JSON с вложенным документом Альтернатива через POST на платформу API Вопрос.

Платформа API возвращает эту ошибку ниже:

Nested documents for "alternatives" attribute are not allowed. Use IRIs instead.

Поискав об этом, я обнаружил, что некоторые люди говорят, что это возможно только с использованием IRI, а некоторые другие люди говорят, что для решения этой проблемы можно использовать контексты денормализации и нормализации, но я не могу найти пример или учебник по этому поводу.

TL;ДР;

Есть ли способ отправить вложенное отношение в сущность POST на платформе API без использования IRI?

Обновлено:

Как было задано, см. ниже два сопоставления сущностей «Вопрос» и «Альтернативный».

Вопрос

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\QuestionRepository")
 * @ApiResource()
 */
class Question implements CreatedAtEntityInterface, UpdatedAtEntityInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Token", inversedBy = "questions")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotBlank()
     */
    private $token;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Question", inversedBy = "question_versions")
     */
    private $question;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Question", mappedBy = "question")
     */
    private $question_versions;

    /**
     * @ORM\Column(type = "integer")
     * @Assert\NotBlank()
     */
    private $version;

    /**
     * @ORM\Column(type = "string", length=100)
     * @Assert\Length(max = "100")
     * @Assert\NotBlank()
     *
     */
    private $name;

    /**
     * @ORM\Column(type = "integer")
     * @Assert\NotBlank()
     */
    private $type;

    /**
     * @ORM\Column(type = "text", length=65535)
     * @Assert\NotBlank()
     * @Assert\Length(max = "65535")
     */
    private $enunciation;

    /**
     * @ORM\Column(type = "string", length=255, nullable=true)
     * @Assert\Length(max = "255")
     */
    private $material;

    /**
     * @ORM\Column(type = "text", length=65535, nullable=true)
     * @Assert\Length(max = "65535")
     */
    private $tags;

    /**
     * @ORM\Column(type = "boolean")
     * @Assert\NotNull()
     */
    private $public;

    /**
     * @ORM\Column(type = "boolean")
     * @Assert\NotNull()
     */
    private $enabled;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     */
    private $createdAt;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     */
    private $updatedAt;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Alternative", mappedBy = "question")
     */
    private $alternatives;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\QuestionProperty", mappedBy = "question")
     */
    private $properties;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\QuestionAbility", mappedBy = "question")
     */
    private $abilities;

    /**
     * @ORM\OneToMany(targetEntity = "QuestionCompetency", mappedBy = "question")
     */
    private $competencies;
}

Альтернатива

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\AlternativeRepository")
 * @ORM\Table(name = "alternatives")
 * @ApiResource()
 */
class Alternative implements CreatedAtEntityInterface, UpdatedAtEntityInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Question", inversedBy = "alternatives")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotBlank()
     */
    private $question;

    /**
     * @ORM\Column(type = "text", length=65535)
     * @Assert\NotBlank()
     * @Assert\Length(max = "65535")
     */
    private $enunciation;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     */
    private $createdAt;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     */
    private $updatedAt;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\AlternativeProperty", mappedBy = "alternatives")
     */
    private $properties;
}

Обновите свой вопрос, включив в него сопоставления API-платформ двух объектов. Пример контекст сериализации см. в разделе api-platform.com/docs/core/serialization/….

Will B. 06.06.2019 15:51

@fyrye Я обновил вопрос, как вы и просили — Бруно де Соуза Роша только что Редактировать

Bruno de Souza Rocha 06.06.2019 18:39

Вы не используете группы сериализаторов или какие-либо другие контексты?

Will B. 06.06.2019 21:58

Нет, я использую только ресурс API

Bruno de Souza Rocha 07.06.2019 18:46

Это видео SymfonyCast показало мне, как именно решить эту проблему, используя аннотацию denormalizationContext! symfonycasts.com/screencast/api-platform/коллекции-создать

Dhia Djobbi 13.04.2021 06:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
6
5
11 358
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

вы можете попробовать реализовать Денормализация

Вопрос:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\QuestionRepository")
 * @ApiResource(
 *     denormalizationContext = {"groups" = {"post"}}
 * )
 */
class Question implements CreatedAtEntityInterface, UpdatedAtEntityInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Token", inversedBy = "questions")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotBlank()
     * @Groups({"post"})
     */
    private $token;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Question", inversedBy = "question_versions")
     * @Groups({"post"})
     */
    private $question;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Question", mappedBy = "question")
     * @Groups({"post"})
     */
    private $question_versions;

    /**
     * @ORM\Column(type = "integer")
     * @Assert\NotBlank()
     * @Groups({"post"})
     */
    private $version;

    /**
     * @ORM\Column(type = "string", length=100)
     * @Assert\Length(max = "100")
     * @Assert\NotBlank()
     * @Groups({"post"})
     */
    private $name;

    /**
     * @ORM\Column(type = "integer")
     * @Assert\NotBlank()
     * @Groups({"post"})
     */
    private $type;

    /**
     * @ORM\Column(type = "text", length=65535)
     * @Assert\NotBlank()
     * @Assert\Length(max = "65535")
     * @Groups({"post"})
     */
    private $enunciation;

    /**
     * @ORM\Column(type = "string", length=255, nullable=true)
     * @Assert\Length(max = "255")
     * @Groups({"post"})
     */
    private $material;

    /**
     * @ORM\Column(type = "text", length=65535, nullable=true)
     * @Assert\Length(max = "65535")
     * @Groups({"post"})
     */
    private $tags;

    /**
     * @ORM\Column(type = "boolean")
     * @Assert\NotNull()
     * @Groups({"post"})
     */
    private $public;

    /**
     * @ORM\Column(type = "boolean")
     * @Assert\NotNull()
     * @Groups({"post"})
     */
    private $enabled;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     * @Groups({"post"})
     */
    private $createdAt;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     * @Groups({"post"})
     */
    private $updatedAt;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Alternative", mappedBy = "question")
     * @Groups({"post"})
     */
    private $alternatives;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\QuestionProperty", mappedBy = "question")
     * @Groups({"post"})
     */
    private $properties;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\QuestionAbility", mappedBy = "question")
     * @Groups({"post"})
     */
    private $abilities;

    /**
     * @ORM\OneToMany(targetEntity = "QuestionCompetency", mappedBy = "question")
     * @Groups({"post"})
     */
    private $competencies;
}

Альтернатива:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\AlternativeRepository")
 * @ORM\Table(name = "alternatives")
 * @ApiResource()
 */
class Alternative implements CreatedAtEntityInterface, UpdatedAtEntityInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Question", inversedBy = "alternatives")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotBlank()
     * @Groups({"post"})
     */
    private $question;

    /**
     * @ORM\Column(type = "text", length=65535)
     * @Assert\NotBlank()
     * @Assert\Length(max = "65535")
     * @Groups({"post"})
     */
    private $enunciation;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     * @Groups({"post"})
     */
    private $createdAt;

    /**
     * @ORM\Column(type = "datetime")
     * @Assert\DateTime()
     * @Groups({"post"})
     */
    private $updatedAt;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\AlternativeProperty", mappedBy = "alternatives")
     * @Groups({"post"})
     */
    private $properties;
}

Теперь вы можете отправить JSON в POST/PUT без IRI:

{
    "token": "/api/tokens/1",
    "question": "string",
    "version": "string",
    "name": "string",
    "type": 0,
    "enunciation": "string",
    "public": true,
    "enabled": true,
    "alternatives": [
        {
            "enunciation": "String",
            "createdAt": "2018-01-01 11:11:11",
            "updatedAt": "2018-01-01 11:11:11"
        }
    ]
}

было именно так! Вы спасли мой день. Большое спасибо.

Bruno de Souza Rocha 07.06.2019 20:16

Хороший ! это решение работает и со мной, спасибо

Irwuin 08.09.2021 22:40

Для всех, у кого проблема с каскадом ошибок сохраняется, вы должны добавить его в свойство OneToMany. То есть для нашего вопроса:

@ORM\OneToMany(targetEntity = "App\Entity\Alternative", mappedBy = "question", cascade = {"persist"})

Другие вопросы по теме