原则不会在通过 API POST 创建的子实体中设置父引用



情况

我们正在开发一个基于Symfony 3的REST API,其中包含Doctrine和FOSRestBundle,使用JMS进行实体(反)序列化。

在 POST 操作期间出现问题,在该操作中,我们创建了一个具有新子实体(玩家)集合的新实体(团队)。JSON 数据已正确反序列化 - 创建一个团队对象,并将所有子实体反序列化为团队对象内玩家集合中的玩家对象。

A. 问题

反序列化后,播放器对象没有团队引用。因此,我们无法存储 Player 对象,因为所需的团队 FK 为空。

我们目前在 PrePersist 事件中"手动"设置玩家 -> 团队关系:

/**
* @ORMPrePersist
*/
public function doSetParentRelation()
{
foreach ($this->getPlayers() as $player) {
$player->setTeam($this);
}
}

在团队.php:

/**
* @var AppBundleEntityPlayer[]
*
* @ORMOneToMany(targetEntity="Player", mappedBy="team", cascade={"persist"})
* @Type("array<AppBundleEntityPlayer>")
* @Groups({"create-version"})
* @AssertValid(traverse="true")
*/
private $players;

在播放器.php中:

/**
* @var AppBundleEntityTeam
*
* @ORMManyToOne(targetEntity="Team", inversedBy="players", fetch="EAGER")
* @ORMJoinColumn(nullable=false)
* @Exclude
*/
private $team;

我想知道是否有更优雅的方法。我们不必向通过 API 调用创建的具有 OneToMany 关系的每个实体添加自定义 PrePersist 事件,而是需要更全局的解决方法。

我们找到了一个适合我们的解决方案,并且不依赖于自定义的 PrePersist 事件。我们已经将JMS设置为使用getter和setter,而不是反射进行(反)序列化:

use JMSSerializerAnnotationAccessType;
/**
* [...]
* @AccessType("public_method")
*/
class Team
{
[...]
}

然后我们添加了一个 setPlayers() 方法,并更改了 addPlayer() 方法,以便在每个玩家中设置团队引用。

/**
* Set players
*
* @param Player[] $players
*/
public function setPlayers(array $players)
{
foreach ($players as $player) {
$this->addPlayer($player);
}
}
/**
* Add player
*
* @param Player $player
*/
public function addPlayer(Player $player)
{
$this->players[] = $player;
$player->setTeam($this);
}

对于对API的POST请求,我们使用表单来获取请求参数并创建实体或执行操作。(请注意,您始终必须在后端提交表单,因为用户不会。请参阅下面的submit方法调用。

$yourEntity = new YourEntity();
$form = $this->createForm(YourFormType::class, $yourEntity)
->submit($request->request->all())
;
if ($form->isValid()) {
// your entity logic
}

或者,根据您的帖子包含的内容,您可能需要先对其进行解码。

$yourEntity = new YourEntity();
$form = $this->createForm(YourFormType::class, $yourEntity);
$data = json_decode($request->getContent(), true);
$form->submit($data);
if ($form->isValid()) {
// your entity logic
}

它与常规表单的唯一区别是您永远不会使用$form->createView();在前端(通过树枝模板)创建表单。您只是始终捕获 POST 请求并将表单用作实体转换器。

希望这有帮助。

相关内容

  • 没有找到相关文章

最新更新