【问题标题】:How to save a Nested Relation with Entity on API Platform如何在 API 平台上保存与实体的嵌套关系
【发布时间】:2019-06-06 13:34:26
【问题描述】:

我有两个实体,QuestionAlternative,其中 Question 与 Alternative 具有 OneToMany 关系,我正在尝试发送带有 嵌套文档的 JSON通过 POST 到 Question API 平台来替代

API 平台在下面返回该错误:

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

搜索它我发现有些人说只有使用 IRI 才有可能,而其他一些人说可以使用非规范化和规范化上下文来解决这个问题,但我找不到有关它的示例或教程。

TL;DR;

有没有办法在不使用 IRI 的情况下将嵌套关系发送到 API 平台上的实体 POST?

更新:

如题,请看下方 Question 和 Alternative 实体的两个映射。

问题

<?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;
}

【问题讨论】:

标签: php symfony api-platform.com


【解决方案1】:

你可以尝试实现Denormalization

问题:

<?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;
}

现在您可以在没有 IRI 的情况下将 JSON 发送到 POST/PUT:

{
    "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"
        }
    ]
}

【讨论】:

  • 就是这样!你拯救了我的下午。非常感谢。
  • 不错的一个!这个解决方案对我也有用,谢谢
【解决方案2】:

对于任何对错误级联持续存在问题的人,您必须将其添加到 OneToMany 属性中。也就是说,对于我们的问题:

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

【讨论】:

    猜你喜欢
    • 2022-06-27
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2021-02-14
    • 2021-02-14
    • 2019-04-01
    • 1970-01-01
    • 2011-01-18
    相关资源
    最近更新 更多