序列化/反序列化继承了JMS Serializer的类

时间:2014-06-30 13:27:18

标签: php symfony doctrine jmsserializerbundle

为了让事情变得简单,我有

/*
 * @JMS\Discriminator(field = "type", map = {
 *     "one": "...\ItemOne",
 *     "two": "...\ItemTwo"
 * })
 */
Abstract Class Item {}
.
.
.
class ItemOne extends Item {/* Contains multiple properties */}
class ItemTwo extends Item {/* Contains multiple properties */}

class Example
{
      /**
        * @var Item[] $items
        * 
        * @ORM\OneToMany(targetEntity="...\Items", mappedBy="holder",cascade={"persist", "remove"})
        */
      protected $items;
}

一旦我使用FOSRestBundle序列化这个实体,一切看起来都不错,我得到了项目数组,每个元素都有一个鉴别器字段但是在反序列化时我得到以下错误

"You must define a type for ...\Example::$items."

所以为了解决这个问题我添加了

/**
  * @ORM\...
  * @JMS\Type("ArrayCollection<...\Item>")
  */
protected $items;

这次序列化的$items似乎仅限于父类Item,所有对象都将丢失与子ItemOne相关的任何属性。 ItemTwo并且将在没有任何鉴别器字段的情况下进行序列化,因此解除错误将失败并显示错误

"The discriminator field name "type" for base-class "...\Item" was not found in input data."

我该如何解决这个问题?

修改 正如@erlangb所说,这似乎是JMS Serializer https://github.com/schmittjoh/JMSSerializerBundle/issues/292

中的常见问题

虽然我无法使用上述解决方法

/**
 * @JMS\Discriminator(field = "type", map = {"car": "...\Test\Car", "moped":"...\Test\Moped"})
 */
abstract class Vehicle {

    public $id;
}

class Car extends Vehicle {

    /**
     *@JMS\Type("integer")
    */
    public $id;
    /**
     *@JMS\Type("string")
     */
    public $car_at;

    /**
     * @JMS\VirtualProperty
     */
    public function getType()
    {
        return 'car';
    }
}

class Moped extends Vehicle {

    /**
     *@JMS\Type("integer")
     */
    public $id;
    /**
     *@JMS\Type("string")
     */
    public $moped_at;

    /**
     * @JMS\VirtualProperty
     */
    public function getType()
    {
        return 'moped';
    }

}

class Saloon
{
    /**
     *@JMS\Type("integer")
     */
    public $id;

    /**
     * @JMS\Type("...\Test\Vehicle")
     */
    public $veichle;
}

    //In controller
    $car = new Car();
    $car->id = 1; 
    $car->car_at = "car";

    $car2 = new Moped();
    $car2->id = 2; 
    $car2->moped_at = "moped";


    $saloon = new Saloon();
    $saloon->veichle = $car2;
    $json = $this->get('jms_serializer')->serialize($saloon,'json');
    $saloon_des = $this->get('jms_serializer')->deserialize($json,'...\Saloon','json');

仍在

 The discriminator field name "type" for base-class "...\Test\Vehicle" was not found in input data. 

或如果我从@JMS\Type移除Saloon->veichle

The discriminator field name "type" of the base-class "...\Test\Vehicle" conflicts with a regular property of the sub-class "...\Test\Moped". 

2 个答案:

答案 0 :(得分:3)

有一个已知问题。几年前我遇到过同样的问题。我不知道他们是否解决了这个问题,但请看一下:https://github.com/schmittjoh/JMSSerializerBundle/issues/292

现在我看到jms serialzier中有这个注释:

/**
* @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"})
*/
abstract class Vehicle { }
class Car extends Vehicle { }
class Moped extends Vehicle { }

您可以设置虚拟属性,如:

class Car extends Vehicle {
    /**
     * @Serializer\VirtualProperty
     */
    public function getType()
    {
        return 'car';
    }
}

class Moped extends Vehicle {
    /**
     * @Serializer\VirtualProperty
     */
    public function getType()
    {
        return 'moped';
    }
}

尝试这种方式

答案 1 :(得分:1)

/**
 * @JMS\Discriminator(field = "type", map = {
 *    "user": "User",
 *    "mod": "Moderator"
 * })
 */
abstract class AbstractUser
{
    /**
     * @JMS\Type("integer")
     */
    public $id;

    /**
     * @JMS\Type("string")
     */
    public $name
}

class Moderator extends AbstractUser
{
    /**
     * @JMS\Type("string")
     */
    public $foo;
}

class User extends AbstractUser
{
    /**
     * @JMS\Type("string")
     */
    public $bar;
}

这是我的测试:

public function testSerializer()
{
    $data = new Moderator();
    $data->foo = 'foo';
    $data->name = 'daniele';
    $serializer = SerializerBuilder::create()->build();
    $jsonContent = $serializer->serialize($data, 'json');

    $obj = $serializer->deserialize($jsonContent, '..MyBundle\...\AbstractUser',     json');
    $this->assertTrue(get_class($obj), 'MyBundle....\Moderator');

}

我已经简化了命名空间,但它可以正常工作

相关问题