我想使用JMSSerializer处理序列化和反序列化的单个对象属性。我们有这个课程:
class Task {
const STATUS_PENDING = 0;
const STATUS_OVER = 1;
protected $status;
/* getter and setter */
public function getStatusLabel()
{
return ['pending', 'over'][$this->getStatus()];
}
public static function getStatusFromLabel($label)
{
return [
'pending' => self::STATUS_PENDING,
'over' => self::STATUS_OVER
][$label];
}
}
我想返回Task的实例抛出一个REST API(使用FOSRestBundle)。问题是我不想返回$status
属性的原始值,而是返回“label”值。
像这样配置序列化:
Task:
exclusion_policy: ALL
properties:
status:
expose: true
type: string
JMS Serializer认为原始值为0或1,但我想在序列化对象中发送'pending'或'over'(使用getStatusLabel
)。并且在反序列化方面做了相反的工作(使用getStatusFromLabel
)。
我对virtual_properties
感到满意,但它只能在血清化方向上起作用。
我尝试使用这样的自定义处理程序:
class TaskHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods()
{
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'Task',
'method' => 'serializeToArray',
]
];
}
public function serializeToArray(JsonSerializationVisitor $visitor, Task $task, array $type, Context $context)
{
$task->setStatus($task->getStatusLabel());
return $visitor->getNavigator()->accept($task, $type, $context);
}
但它显然不起作用!
如何在血清化和反序列化方向上调用我的自定义getter?
答案 0 :(得分:10)
我终于找到了答案。
首先,我必须创建一个这样的事件子网:
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\PreDeserializeEvent;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
class TaskSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
[
'event' => Events::PRE_SERIALIZE,
'format' => 'json',
'class' => 'Task', // fully qualified name here
'method' => 'onPreSerializeTaskJson',
],
[
'event' => Events::PRE_DESERIALIZE,
'format' => 'json',
'class' => 'Task',
'method' => 'onPreDeserializeTaskJson',
]
];
}
public function onPreSerializeTaskJson(PreSerializeEvent $event)
{
/** @var Task $task */
$task = $event->getObject();
$task->setStatus($task->getStatusLabel());
}
public function onPreDeserializeTaskJson(PreDeserializeEvent $event)
{
$data = $event->getData();
$data['status'] = Task::getStatusFromLabel($data['status']);
$event->setData($data);
}
}
我在这做什么:
对于此解决方案,必须将字段(expose: true
或@Expose
)公开给序列化程序。
然后我将订阅者声明为Symfony中的服务,标记为jms_serializer.event_subscriber
。
serializer.subscriber.task:
class: %serializer.subscriber.task.class% # TaskSubscriber class path
tags:
- { name: jms_serializer.event_subscriber }
它有效。
这是我发现序列化和反序列化的最佳方式。也可以在post_serialize和post_deserialize事件上操作数据。例如,在序列化对象上添加新字段:
use JMS\Serializer\EventDispatcher\ObjectEvent;
public function onPostSerializeTaskJson(ObjectEvent $event)
{
/** @var Task $task */
$task = $event->getObject();
$event->getVisitor()->addData('nb_related', count($task->getRelatedTasks()));
}