问题:
在序列化一系列Doctrine enitities时,虽然这些项目是空的,但该集合仍然有2个项目。
背景:
我有一些实体相互延伸B
延伸A
和C
延伸B
。在实体Test
中,我有一个包含B
类型对象的数组。在序列化时,$test
将具有预期值(包含两个项目的集合)。
$test
包含一个变量(数组)collection
数组中的一个项目属于B
类型,另一个类型为C
。
$sTest
将获得两个项目的集合,尽管这些项目是空的。
这是$sTest
$test
"{"collection":[[],[]]}"
中的字符串看起来的样子
测试脚本:
$test = new Test();
$b = new B();
$b->setToken('asdf');
$b->setName('asdf');
$c = new C();
$c->setToken('asdf');
$c->setName('asdf');
$c->setDescription('asdf');
$test->addCollection($b);
$test->addCollection($c);
//Serialize
$serializer = $this->container->get('serializer');
$sTest = $serializer->serialize($test, 'json');
//Deserialize
$deserializer = $this->container->get('serializer');
$dTest = $deserializer->deserialize($sTest, 'Acme\DemoBundle\Entity\Test', 'json');
$em = $this->getDoctrine()->getManager();
$em->merge($dTest);
$em->flush();
A:
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({"a" = "Acme\DemoBundle\Entity\A", "b" = "Acme\DemoBundle\Entity\B", "c" = "Acme\DemoBundle\Entity\C"})
*
* @JMS\ExclusionPolicy("None")
* @JMS\Discriminator(field = "type", map = {
* "a": "Acme\DemoBundle\Entity\A",
* "b": "Acme\DemoBundle\Entity\B",
* "c": "Acme\DemoBundle\Entity\C", *
* })
*/
class A {
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=100)
*/
protected $token;
public function setToken($token){
$this->token = $token;
}
/**
* @JMS\VirtualProperty
* @JMS\SerializedName("type")
*/
public function getDiscr()
{
return 'a';
}
}
B:
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* @ORM\Entity
* @JMS\ExclusionPolicy("None")
*/
class B extends A {
/**
* @ORM\Column(type="string", length=100)
*/
protected $name;
/**
* @ORM\ManyToOne(targetEntity="Acme\DemoBundle\Entity\Test", inversedBy="collection")
* @ORM\JoinColumn(name="TestId", referencedColumnName="id")
*/
private $test;
public function setName($name) {
$this->name = $name;
}
/**
* @JMS\VirtualProperty
* @JMS\SerializedName("type")
*/
public function getDiscr() {
return 'b';
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set token
*
* @param string $token
* @return B
*/
public function setToken($token)
{
$this->token = $token;
return $this;
}
/**
* Get token
*
* @return string
*/
public function getToken()
{
return $this->token;
}
/**
* Set test
*
* @param \Acme\DemoBundle\Entity\Test $test
* @return B
*/
public function setTest(\Acme\DemoBundle\Entity\Test $test = null)
{
$this->test = $test;
return $this;
}
/**
* Get test
*
* @return \Acme\DemoBundle\Entity\Test
*/
public function getTest()
{
return $this->test;
}
}
C:
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* @ORM\Entity
* @JMS\ExclusionPolicy("None")
*/
class C extends B {
/**
* @ORM\Column(type="text")
*/
protected $description;
public function setDescription($description) {
$this->description = $description;
}
/**
* @JMS\VirtualProperty
* @JMS\SerializedName("type")
*/
public function getDiscr() {
return 'c';
}
}
测试:
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* @ORM\Entity
*/
class Test {
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\OneToMany(targetEntity="Acme\DemoBundle\Entity\B", mappedBy="test", cascade={"all"})
* @JMS\Type("ArrayCollection<'Acme\DemoBundle\Entity\B'>")
*/
private $collection;
/**
* Constructor
*/
public function __construct()
{
$this->collection = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add collection
*
* @param \Acme\DemoBundle\Entity\B $collection
* @return Test
*/
public function addCollection(\Acme\DemoBundle\Entity\B $collection)
{
$this->collection[] = $collection;
return $this;
}
/**
* Remove collection
*
* @param \Acme\DemoBundle\Entity\B $collection
*/
public function removeCollection(\Acme\DemoBundle\Entity\B $collection)
{
$this->collection->removeElement($collection);
}
/**
* Get collection
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCollection()
{
return $this->collection;
}
}
答案 0 :(得分:1)
Test::$collection
正如NDM所指出的,Test::$collection
的注释不正确,在引用类型时需要省略引号:
diff --git a/src/Test.php b/src/Test.php
index c0da0c3..a5ea94e 100644
--- a/src/Test.php
+++ b/src/Test.php
@@ -19,7 +19,7 @@ class Test {
/**
* @ORM\OneToMany(targetEntity="Acme\DemoBundle\Entity\B", mappedBy="test", cascade={"all"})
- * @JMS\Type("ArrayCollection<'Acme\DemoBundle\Entity\B'>")
+ * @JMS\Type("ArrayCollection<Acme\DemoBundle\Entity\B>")
*/
private $collection;
供参考,请参阅http://jmsyst.com/libs/serializer/master/reference/annotations#type。
A::$token
和B::$name
在修复Test::$collection
的注释后尝试序列化会导致抛出以下异常
JMS\Serializer\Exception\RuntimeException:
You must define a type for Acme\DemoBundle\Entity\B::$name.
和
JMS\Serializer\Exception\RuntimeException:
You must define a type for Acme\DemoBundle\Entity\A::$token.
为A::$token
添加缺少的注释:
diff --git a/src/A.php b/src/A.php
index eb89b36..f806581 100644
--- a/src/A.php
+++ b/src/A.php
@@ -29,6 +29,7 @@ class A {
/**
* @ORM\Column(type="string", length=100)
+ * @JMS\Type("string")
*/
protected $token;
和B::$name
:
diff --git a/src/B.php b/src/B.php
index 71a8b0b..7b448c6 100644
--- a/src/B.php
+++ b/src/B.php
@@ -13,6 +13,7 @@ class B extends A {
/**
* @ORM\Column(type="string", length=100)
+ * @JMS\Type("string")
*/
protected $name;
解决了问题并从上面给出了您的脚本,$test
可以成功序列化为
{
"collection":[
{
"type":"b",
"token":"asdf",
"name":"asdf"
},
{
"type":"c",
"token":"asdf",
"name":"asdf",
"description":"asdf"
}
]
}
答案 1 :(得分:0)
对于有些不同的要求(JSON),我创建了一个基本实体并按如下方式实现了行为:
function jsonSerialize()
{
$arr = get_object_vars($this);
foreach ($arr as $key => $var) {
unset($arr[$key]);
if (method_exists($var, 'jsonSerialize')) {
$var = $var->jsonSerialize();
} elseif ( $var instanceof \DateTime) {
$var = $var->format('Y-m-d\TH:i:s\Z');
}
$arr[strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $key))] = $var;
}
return $arr;
}