php - 使用继承序列化包含对象的 Doctrine 数组

标签 php symfony doctrine-orm jmsserializerbundle

问题:

当序列化 Doctrine 实体的集合时,该集合仍将有 2 个项目,尽管这些项目是空的。

背景:

我有几个相互扩展的实体 B延伸AC延伸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();

答:

<?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';
    }

}

乙:

<?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;
    }
}

最佳答案

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::$tokenB::$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"
    }
  ]
}

关于php - 使用继承序列化包含对象的 Doctrine 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25265039/

相关文章:

php - PHP 文件上传问题

php - MySQL 事务 - 查询更改数据库而不提交?

来自mysql结果的php多维数组

Symfony2 <a> 链接 'post' 或 'delete' 或 'put' 方法

php - 从多对多表学说 symfony 2 中删除记录

PHP:以月年格式获取过去 6 个月的数据

php - 交响乐 2.4.2 : You cannot create a service ("request") of an inactive scope ("request")

symfony - 返回oci错误号?

symfony - Sonata Admin => 仅选择给定的鉴别器映射类型

sql - Doctrine 2 - 单表继承 - 子实体的访问属性