带有抽象类Symfony2的JMSSerializerBundle


JMSSerializerBundle with abstract class - Symfony2

我想序列化和反序列化具有依赖关系的实体,但无法序列化与抽象类有关的元素。

层次结构:

测试-->几个Calls,其中Call类是一个抽象类,由TestCallExecuteQuery扩展(与$conditions问题相同)

Test.php:

/**
 * @ORM'Entity(repositoryClass="Gedmo'Sortable'Entity'Repository'SortableRepository")
 * @ORM'Table(name="cfa_test")
 * @JMSSer'ExclusionPolicy("all")
 */
class Test
{
    /**
     * @ORM'OneToMany(targetEntity="TestCall", mappedBy="test", cascade={"all"}, orphanRemoval=true)
     * @JMSSer'Expose
     * @JMSSer'Groups({"export"})
     * @JMSSer'Type("ArrayCollection<App'Bundle'CapFileAnalyzerBundle'Entity'TestCall>")
     */
    protected $calls;
    /**
     * @ORM'OneToMany(targetEntity="TestCondition", mappedBy="test", cascade={"all"}, orphanRemoval=true)
     * @JMSSer'Expose
     * @JMSSer'Groups({"export"})
     * @JMSSer'Type("ArrayCollection<App'Bundle'CapFileAnalyzerBundle'Entity'TestCondition>")
     */
    protected $conditions;

TestCall.php:

/**
 * @ORM'Entity
 * @ORM'InheritanceType("SINGLE_TABLE")
 * @ORM'Table(name="cfa_test_call")
 * @ORM'DiscriminatorColumn(name="type", type="string")
 * @ORM'DiscriminatorMap({
 *      "executeQuery" = "App'Bundle'CapFileAnalyzerBundle'Entity'TestCallExecuteQuery",
 *      "call" = "App'Bundle'CapFileAnalyzerBundle'Entity'TestCall"
 * })
 * @JMSSer'ExclusionPolicy("all")
 * @JMSSer'Discriminator(field="serializedType", map={
 *      "executeQuery"="App'Bundle'CapFileAnalyzerBundle'Entity'TestCallExecuteQuery",
 *      "call" = "App'Bundle'CapFileAnalyzerBundle'Entity'TestCall"
 * })
 */
abstract class TestCall
{
    /**
     * @JMSSer'Expose
     * @JMSSer'Groups({"export"})
     */
    protected $type = 'call';
    /**
     * @ORM'Id
     * @ORM'Column(name="id", type="integer")
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @ORM'ManyToOne(targetEntity="Test", inversedBy="calls")
     */
    protected $test;
  /**
     * @JMSSer'VirtualProperty()
     * @JMSSer'SerializedName("serializedType")
     */
    public function getDiscr()
    {
        return $this->type;
    }

TestCallExecuteQuery.php:

/**
 * @ORM'Entity
 * @JMSSer'ExclusionPolicy("all")
 */
class TestCallExecuteQuery extends TestCall
{
    protected $type = 'executeQuery';
    /**
     * @ORM'Column(name="`query`", type="text")
     * @JMSSer'Expose
     * @JMSSer'Groups({"export"})
     */
    protected $query;
    /**
     * @ORM'Column(name="`return`", type="string", nullable=true)
     * @JMSSer'Expose
     * @JMSSer'Groups({"export"})
     */
    protected $return;

所以我遵循了互联网上的指示:

  • 每个类中都有@JMSSer'ExclusionPolicy("all")@JMSSer'Expose注释
  • 抽象类TestCall顶部的@JMSSer'Discriminator注释与扩展类(TestcallExecuteQuery)映射

但是。。当我序列化时,我只得到TestCall的类型属性,而没有得到TestCallExecuteQuery:中定义的queryreturn属性

{"tests":[{"calls":[{"type":"executeQuery"},{"type":"executeQuery"}], ... }

我知道这是可能的,因为我得到过一次,但即使时光倒流,我也无法重现。。

{"tests":[{"calls":[{"query":"SELECT * FROM table","return":"return_1"}], ... }

编辑:

好的,我可能通过改变Test.php:得到了queryreturn

/**
 * @JMSSer'Type("ArrayCollection<App'Bundle'CapFileAnalyzerBundle'Entity'TestCall>")
 */
    protected $calls;

收件人:

/**
 * @JMSSer'Type("ArrayCollection<App'Bundle'CapFileAnalyzerBundle'Entity'TestCallExecuteQuery>")
 */
    protected $calls;

我做错了什么?

好吧!我在几天失去理智后找到了解决办法!

解决方案是创建两个事件侦听器PreSerialize和PostSerialize

首先,我在TestCall.php(抽象类)中删除了这个部分:

/**
 * @JMSSer'VirtualProperty()
 * @JMSSer'SerializedName("serializedType")
 */
public function getDiscr()
{
    return $this->type;
}

并在TestCallExecuteQuery.php(扩展程序类)中添加了这些注释:

/**
 * @JMSSer'Type("string")
 * @JMSSer'Expose
 * @JMSSer'Groups({"export"})
 */
protected $type = 'executeQuery';

我的听众是这样的:

<?php
namespace App'Bundle'CapFileAnalyzerBundle'EventListener;
use JMS'Serializer'EventDispatcher'Events;
use JMS'Serializer'EventDispatcher'EventSubscriberInterface;
use JMS'Serializer'EventDispatcher'ObjectEvent;
use JMS'Serializer'EventDispatcher'PreSerializeEvent;
class JMSSerializerListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            ['event' => Events::PRE_SERIALIZE, 'method' => 'onPreSerialize'],
            ['event' => Events::POST_SERIALIZE, 'method' => 'onPostSerialize']
        ];
    }
    /**
     * @param PreSerializeEvent $event
     */
    public function onPreSerialize(PreSerializeEvent $event)
    {
        $object = $event->getObject();
        if (is_object($object) &&
            is_subclass_of($object, 'App'Bundle'CapFileAnalyzerBundle'Entity'TestCall') &&
            get_class($object) !== $event->getType()['name']
        ) {
            $event->setType(get_class($event->getObject()));
        }
    }
    /**
     * @param ObjectEvent $event
     */
    public function onPostSerialize(ObjectEvent $event){
        $object = $event->getObject();
        if (is_object($object) &&
            is_a($object, 'App'Bundle'CapFileAnalyzerBundle'Entity'TestCallExecuteQuery')) {
            $event->getVisitor()->addData("serializedType", $object->getType());
        }
    }
}

听众声明:

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    <parameters>      
        <parameter key="cfa.events.jmsserializer_listener.class">App'Bundle'CapFileAnalyzerBundle'EventListener'JMSSerializerListener</parameter>
    </parameters>
    <services>
         <service id="cfa.events.jmsserializer_listener" class="%cfa.events.jmsserializer_listener.class%">
            <tag name="jms_serializer.event_subscriber"/>
        </service>
    </services>
</container>

我解释一下:

  1. 预Seralize事件

如果要序列化的对象是我的抽象类(在我的情况下是TestCall)的子类,我必须强制将事件对象的类型序列化到相关的子类(在我们的情况下为TestCallExecuteQuery)中。事实上,传递了正确的对象(TestCallExecuteQuery),但它与其父类(抽象类TestCall)映射

$event对象转储:

PreSerializeEvent {#977 ▼
  -object: TestCallExecuteQuery {#981 ▼
    #type: "executeQuery"
    #query: "SELECT * FROM table_name"
    #return: "return_3"
    #id: 2
    #test: Test {#948 ▶}
  }
  #type: array:2 [▼
    "name" => "App'Bundle'CapFileAnalyzerBundle'Entity'TestCall"
    "params" => []
  ]
  -context: SerializationContext {#420 ▶}
}
  1. PostSerialze事件

如果序列化对象是我的子类,我会添加访问者属性(甚至不是虚拟自定义)。。

NB:JMSSerializeBundle不会序列化直接添加到类中的"虚拟"属性,例如通过这样的方法:

public function createProperty($name, $value) {    
     $this->{$name} = $value;    
}

也许鉴别器/虚拟属性像JMSSerializerBundle中那样添加,这就是为什么它们没有序列化的原因。。真的不知道

相关文章:
  • 没有找到相关文章