php - online - Serialize Doctrine array que contiene objetos usando herencia
serialize php ejemplo (2)
Problema :
Al serializar una colección de entidades de Doctrine, la colección aún tendrá 2 elementos aunque los elementos estén vacíos.
Antecedentes :
Tengo algunas entidades que se extienden entre sí B
extiende A
y C
extiende B
En la Test
entidad, tengo una matriz con objetos del tipo B
$test
tendrá los valores esperados (colección con dos elementos) en el momento de la serialización.
$test
contiene una collection
variable (matriz) uno de los elementos en la matriz es del tipo B
y uno de tipo C
$sTest
obtendrá la colección de dos elementos aunque los artículos estén vacíos. Así es como se ve la cadena en $sTest
después de la serialización de $test
"{"collection":[[],[]]}"
Secuencia de comandos de prueba:
$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();
UN:
<?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'';
}
}
SEGUNDO:
<?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;
}
}
DO:
<?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'';
}
}
Prueba:
<?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;
}
}
Anotación incorrecta para Test::$collection
Como señaló NDM , la anotación para Test::$collection
no es correcta, debe omitir las comillas al hacer referencia al tipo:
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;
Para referencia, vea http://jmsyst.com/libs/serializer/master/reference/annotations#type .
Anotaciones faltantes para A::$token
y B::$name
Intentando serializar después de corregir la anotación para resultados de la Test::$collection
en las siguientes excepciones lanzadas
JMS/Serializer/Exception/RuntimeException:
You must define a type for Acme/DemoBundle/Entity/B::$name.
y
JMS/Serializer/Exception/RuntimeException:
You must define a type for Acme/DemoBundle/Entity/A::$token.
Agregar la anotación faltante para 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;
y para 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;
resuelve el problema y dado su guión desde arriba, $test
se puede serializar con éxito para
{
"collection":[
{
"type":"b",
"token":"asdf",
"name":"asdf"
},
{
"type":"c",
"token":"asdf",
"name":"asdf",
"description":"asdf"
}
]
}
Para un requisito algo diferente (JSON) he creado una entidad base e implementado el comportamiento de la siguiente manera:
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;
}