【问题标题】:Format input and output fields with JMSSerializer (handle single property)使用 JMSSerializer 格式化输入和输出字段(处理单个属性)
【发布时间】:2013-12-19 17:01:33
【问题描述】:

我想使用 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];
    }
}

我想返回一个 REST API 的 Task 实例(使用 FOSRestBundle)。问题是我不想返回 $status 属性的原始值,而是“标签”值。

像这样配置我的序列化:

Task:
    exclusion_policy: ALL
    properties:
        status:
            expose: true
            type: string

JMS 序列化程序会考虑原始值 0 或 1,但我想在我的序列化对象中发送“待定”或“结束”(使用 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?

【问题讨论】:

    标签: jmsserializerbundle


    【解决方案1】:

    我终于找到了答案。

    首先我必须像这样创建一个事件订阅者:

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

    我在这里做什么:

    • 在序列化之前,我用标签设置了我的Task对象的状态值
    • 在反序列化之前,我将序列化对象的值从标签更改为原始整数值

    对于此解决方案,必须将字段(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()));
    }
    

    【讨论】:

    • 感谢分享。 @all 考虑“类”的完全限定名称必须不带反斜杠(难以调试)。
    猜你喜欢
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多