私は Symfony2 プロジェクトで Doctrine+JMSserializer を使用していますが、典型的な JMS の「デシリアライズ」および Doctrine の「永続化」操作中に、関連するエンティティとそのデータが侵害される可能性があるという問題を発見しました。
$data = [
'locale' => 'en',
'name' => $this->faker->sentence(),
'content' => $this->faker->text(),
'subject' => [
'id' => $page->getId(),
'name' => 'new name' // <-- compromised property
]
];
$rawPayload = json_encode($data);
$entity = $this->serializer->deserialize(
$rawPayload,
$resolvedClass,
'json'
);
そして、新しい $entity 関連の Page エンティティ名の通常の永続化操作の後、変更されるため、問題になります。
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
目標は、レビューのページ ID を設定することですが、他のプロパティの変更を防止します。そうしないと、ページ エンティティが危険にさらされる可能性があります。注釈、教義設定などを変更してこの問題を解決しようとしました。この問題を自然な方法で解決する方法はありますか?
レビューとページのエンティティ:
use Aisel\ReviewBundle\Entity\Review as BaseReview;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation as JMS;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Review
*
* @ORM\HasLifecycleCallbacks()
* @ORM\Table(name="aisel_page_review")
* @ORM\Entity(repositoryClass="Aisel\ResourceBundle\Repository\CollectionRepository")
* @JMS\ExclusionPolicy("all")
*/
class Review extends BaseReview
{
/**
* @var Page
* @Assert\NotNull()
* @ORM\ManyToOne(targetEntity="Aisel\PageBundle\Entity\Page", inversedBy="pages")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="page_id", referencedColumnName="id", nullable=false)
* })
* @JMS\Type("Aisel\PageBundle\Entity\Page")
* @JMS\Expose
* @JMS\MaxDepth(2)
*/
private $subject;
/**
* @return Page
*/
public function getSubject()
{
return $this->subject;
}
/**
* @param Page $subject
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
}
<?php
namespace Aisel\PageBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use JMS\Serializer\Annotation as JMS;
use Aisel\ResourceBundle\Domain\UrlInterface;
use Aisel\PageBundle\Entity\Node;
use Aisel\PageBundle\Entity\Review;
use Aisel\UserBundle\Entity\User;
use Aisel\ResourceBundle\Domain\IdTrait;
use Aisel\ResourceBundle\Domain\UpdateCreateTrait;
use Aisel\ResourceBundle\Domain\MetaTrait;
use Aisel\ResourceBundle\Domain\LocaleTrait;
use Aisel\ResourceBundle\Domain\StatusTrait;
use Aisel\ResourceBundle\Domain\NameTrait;
use Aisel\ResourceBundle\Domain\ContentTrait;
use Aisel\ResourceBundle\Domain\CommentStatusTrait;
/**
* Page
*
* @author Ivan Proskuryakov <volgodark@gmail.com>
*
* @ORM\HasLifecycleCallbacks()
* @ORM\Table(name="aisel_page")
* @ORM\Entity(repositoryClass="Aisel\ResourceBundle\Repository\CollectionRepository")
* @JMS\ExclusionPolicy("all")
*/
class Page implements UrlInterface
{
use IdTrait;
use NameTrait;
use ContentTrait;
use LocaleTrait;
use StatusTrait;
use CommentStatusTrait;
use MetaTrait;
use UpdateCreateTrait;
/**
* @var ArrayCollection
* @ORM\ManyToMany(targetEntity="Aisel\PageBundle\Entity\Node")
* @ORM\JoinTable(
* name="aisel_page_page_node",
* joinColumns={@ORM\JoinColumn(name="page_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="node_id", referencedColumnName="id")}
* )
* @JMS\Type("ArrayCollection<Aisel\PageBundle\Entity\Node>")
* @JMS\Expose
* @JMS\MaxDepth(2)
* @JMS\Groups({"collection","details"})
*/
private $nodes;
/**
* @var ArrayCollection<Aisel\PageBundle\Entity\Review>
* @ORM\OneToMany(targetEntity="Aisel\PageBundle\Entity\Review", mappedBy="subject", cascade={"remove"})
* @ORM\OrderBy({"createdAt" = "DESC"})
* @JMS\Expose
* @JMS\MaxDepth(2)
* @JMS\Type("ArrayCollection<Aisel\PageBundle\Entity\Review>")
* @JMS\Groups({"collection","details"})
*/
private $reviews;