我有一个名为 Submission
的实体类型。 Submission
与 SurveyData
实体类型具有 OneToOne 关系。
SurveyData 实体实际上是一个映射的父类(super class)。它最终将有几十个实体子类,用于存储来自不同调查的数据。
根据文档,我创建了一个自定义 Normalizer,它根据 type
键处理非规范化:
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
属性添加到嵌入式调查响应中。我不确定这是不是因为它是一个不能为空的OneToOne,所以它是内部跟踪的:
{
"@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
}
}
真正的问题是PUT
和PATCH
请求失败。
对于 PATCH
请求,我可以更新父提交实体中的字段。但是,如果我发送以下请求,Submission 和 SurveyData 实体将从数据库中删除,并且我从 API 中收到以下错误:
“实体 App\\Entity\\Submission@000000002116ebc30000000012ca4827 未被管理。如果实体从数据库中获取或通过 EntityManager#persist 注册为新实体,则该实体被管理”,
要点包括跟踪的整个响应:https://gist.github.com/brianV/c32661186c91b49b013017dde77d5d4a
这是触发错误的 PATCH
请求示例:
{
"user": "brian",
"surveyData": {
"type": "MonthlyTotals",
"num_deliveries": 100
}
}
每个 PUT 请求也会发生这种情况(我在其中包含整个替换提交实体)。
在普通的 Symfony 和 Doctrine 中,这个解决方案会很好用,但它似乎会破坏 API 平台。
根据评论请求,这是提交
实体注释:
/**
* @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;
在此先感谢您的帮助!
最佳答案
当您使用 Submission
URL 时,请确保您的 SurveyData
属性已使用 api_platform.jsonld.normalizer.item
服务进行规范化.
我假设你已经关注了those steps嵌入你的对象?嗯,和描述的一样here ,因为您没有在嵌入对象中提供 @id
属性,Api-Platform 认为您正在推送一个新对象而不是编辑当前对象,这就是为什么学说哭了(你的错误信息):这个新对象没有注册。
自动注册这个新对象的最简单方法是在您的 Submission::$surveyData
属性上添加一个 cascade={"persist"}
注释属性:
class Submission
{
/**
* @OneToOne(targetEntity="App\Entity\SurveyData", cascade={"persist"})
*/
private $surveyData,
}
但您也可以使用 EntityManagerInterface::persist()
方法。
注意:我不确定PATCH
方法是否与嵌入式对象完全兼容,我记得github 上有一些关于此的问题。
关于php - API 平台 : Normalizing and Denormalizing inheritance-mapped Doctrine entities,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63529872/