我想序列化和反序列化具有依赖关系的实体,但无法序列化与抽象类有关的元素。
层次结构:
测试-->几个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
:中定义的query
或return
属性
{"tests":[{"calls":[{"type":"executeQuery"},{"type":"executeQuery"}], ... }
我知道这是可能的,因为我得到过一次,但即使时光倒流,我也无法重现。。
{"tests":[{"calls":[{"query":"SELECT * FROM table","return":"return_1"}], ... }
编辑:
好的,我可能通过改变Test.php
:得到了query
和return
/**
* @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>
我解释一下:
- 预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 ▶}
}
- PostSerialze事件
如果序列化对象是我的子类,我会添加访问者属性(甚至不是虚拟自定义)。。
NB:JMSSerializeBundle不会序列化直接添加到类中的"虚拟"属性,例如通过这样的方法:
public function createProperty($name, $value) {
$this->{$name} = $value;
}
也许鉴别器/虚拟属性像JMSSerializerBundle中那样添加,这就是为什么它们没有序列化的原因。。真的不知道