提问者:小点点

API平台:规范化和反规范化继承映射原则实体


我有一个名为提交内容的实体类型。提交与 SurveyData 实体类型具有一对一关系。

SurveyData 实体实际上是一个映射的超类。它最终将有几十个用于存储来自不同调查数据的实体子类。

根据文档,我创建了一个自定义规范化器,它基于类型键处理非规范化:

  public function denormalize($data, string $type, string $format = null, array $context = [])
  {
    if ($type === 'App\Entity\SurveyData\SurveyData') {
      $class = 'App\Entity\SurveyData\\' . $data['type'];
      $context['resource_class'] = $class;
    }

    $context[self::ALREADY_CALLED] = true;

    return $this->denormalizer->denormalize($data, 'App\Entity\SurveyData\\' . $data['type'], $format, $context);
  }

有了这个,我可以完美地创建一个嵌入了SurveyData的新提交。下面是我发送给POST请求的JSON示例:

{
    "facility": "/api/facilities/1",
    "survey": "/api/surveys/monthly_totals",
    "dateDetail": "Q1 2020",
    "surveyData": {
      "type": "MonthlyTotals",
      "num_deliveries": 50,
      "num_cesarean": 30,
      "num_epidural_anesthesia": 15
    },
    "created": "2020-08-14T18:59:49.218Z",
    "updated": "2020-08-14T18:59:49.218Z",
    "user": "brian",
    "status": "complete"
}

但是,当我通过 GET 获取集合或单个提交实体时,API 平台返回的响应忽略了将 @id 属性添加到嵌入式调查响应中。我不确定这是否是因为它是一个不能为空的一对一,所以它在内部被跟踪:

{
            "@id": "/api/submissions/2",
            "@type": "Submission",
            "id": 2,
            "facility": "/api/facilities/1",
            "survey": "/api/surveys/monthly_totals",
            "dateDetail": "Q1 2020",
            "created": "2020-08-14T18:59:49+00:00",
            "updated": "2020-08-14T18:59:49+00:00",
            "user": "brian",
            "status": "complete",
            "surveyData": {
                "num_deliveries": 50,
                "num_cesarean": 30,
                "num_epidural_anesthesia": 15
            }
        }

真正的问题是PUTPATCH请求失败。

对于< code>PATCH请求,我可以更新父提交实体中的字段。但是,如果我发送以下请求,Submission和SurveyData实体将从数据库中删除,并且我会从API中得到以下错误:

“实体应用\\实体\\Submission@000000002116ebc30000000012ca4827不受管理。如果实体从数据库中获取或通过 EntityManager#persist 注册为新实体,则对其进行管理“,

整个反应的要点包括一个痕迹:https://gist.github.com/brianV/c32661186c91b49b013017dde77d5d4a

下面是一个触发错误的< code>PATCH请求的示例:

{
    "user": "brian",
    "surveyData": {
        "type": "MonthlyTotals",
        "num_deliveries": 100
    }
}

每个PUT请求也会发生这种情况(其中我包括了整个替换提交实体)。

简单的Symfony

根据注释请求,以下是提交实体注释:

/**
 * @ApiResource(
 *   normalizationContext={"groups"={"submission"}},
 *   denormalizationContext={"groups"={"submission"}},
 *   itemOperations={
 *     "get"={
 *       "method"="GET",
 *       "access_control"="is_granted('view', object)",
 *     },
 *     "put", "patch", "delete",
 *   },
 * )
 * @ORM\Entity(repositoryClass="App\Repository\SubmissionRepository")
 * @CustomAssert\SubmissionDataIsValid
 */
class Submission
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"submission"})
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Facility")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"submission"})
     */
    private $facility;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Patient", inversedBy="submissions")
     * @Groups({"submission"})
     */
    private $patient;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"submission"})
     */
    private $survey;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"submission"})
     */
    private $dateDetail;

    /**
     * @ORM\Column(type="datetime")
     * @Assert\Type("\DateTimeInterface")
     * @Groups({"submission"})
     */
    private $created;

    /**
     * @ORM\Column(type="datetime")
     * @Assert\Type("\DateTimeInterface")
     * @Groups({"submission"})
     */
    private $updated;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"submission"})
     */
    private $user;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"submission"})
     */
    private $status;

    /**
     * @ORM\OneToOne(targetEntity="App\Entity\SurveyData\SurveyData", inversedBy="submission", cascade={"persist", "remove"}, orphanRemoval=true, fetch="EAGER")
     * @Groups({"submission"})
     */
    private $surveyData;

提前感谢任何帮助!


共1个答案

匿名用户

确保使用api_platform.jsonld.normalizer对SurveyData属性进行了规范化。当您使用提交URL时,项目服务。

我假设您已经按照这些步骤嵌入了您的对象?嗯,正如这里所描述的,因为你没有在你的嵌入对象中提供一个< code>@id属性,Api-Platform认为你在推一个新的对象,而不是编辑当前的对象,这就是为什么doctrine大叫(你的错误消息):这个新对象没有注册。

自动注册这个新对象的最简单方法是在提交::$调查数据属性上添加层叠={"持续"}注释属性:

class Submission
{
    /**
     * @OneToOne(targetEntity="App\Entity\SurveyData", cascade={"persist"})
     */
    private $surveyData,
}

但您也可以使用EntityManagerInterface::persist()方法。

注意:我不确定PATCH方法是否与嵌入式对象完全兼容,我记得github上的一些问题。