复杂的序列化

时间:2017-01-09 12:24:15

标签: symfony jmsserializerbundle jms-serializer

例如,我有两个实体:main(父)实体(例如User)和依赖实体(Post)。我想使用JMS Serializer序列化User实体以及其第一个发布日期的附加信息。存储在DB中的发布日期是timestamp int,但是我想用我的帮助程序(只是一个服务)将它序列化,它将int转换为带有某种格式的sting。

尝试在实体类中使用方法创建virtual_property,但未能将我的帮助器注入实体类。解决它的唯一方法是将自己序列化为控制器:

public function someAction()
{
    $serializedUser = $this->serializeEntity($user);
}

public function serializeEntity(User $user)
{
    // JMS serialization
    $user = $this->get('jms_serializer')->serialize($user, 'array');

    if ($user->getPosts()->count()) {
        $post = $user->getPosts()->first();
        $user['first_post_date'] = $this->get('my_helper_service')->dateFormat($post->getDate());
    }

    return $user;
}

注意:这个例子是合成的,在现实世界中我有更复杂的方法,而不仅仅是日期格式化程序。但主要观点是一样的。

我觉得应该有更好的方法来做到这一点。

2 个答案:

答案 0 :(得分:3)

Dmtry的解决方案应该适合您的情况。

在这种情况下,事件监听器/订户是最佳解决方案。

更通用的解决方案,即使对象也能工作,并且会触发JMS序列化程序的整个事件系统部分(Dmtry的解决方案仅适用于基元,仅适用于JSON / YAML,而不是XML),是:

class MyFormatter implements EventSubscriberInterface
{

    public static function getSubscribedEvents()
    {
        return array(
            array(
                'event' => 'serializer.post_serialize', 
                'method' => 'onPostSerialize',
                'class' => 'YourEntity'
            ),
        );
    }

    public function __construct(MyFormatter $foermatter)
    {
        $this->formatter = $formatter;
    }

    public function onPostSerialize(ObjectEvent $event)
    {
        $visitor = $event->getVisitor();
        $context = $event->getContext();

        $timestamp = $event->getObject()->getTimestamp();
        $formattedTime = $this->formatter->format($timestamp);

        $metadata = new StaticPropertyMetadata('stdClass', 'first_post_date', $formattedTime);

        $visitor->visitProperty($metadata, $formattedTime, $context);
    }
}
序列化程序忽略

stdClass ...

答案 1 :(得分:1)

当然,还有更好的方法。它被称为序列化事件。

http://jmsyst.com/libs/serializer/master/event_system

您创建活动订阅者

my_bundle.serializer_subscriber:
    class: MyBundle\Serializer\MyEntitySerializerSubscriber
    arguments:
        - @bundle.time_formatter
    tags:
        - { name: jms_serializer.event_subscriber }

然后只需在监听器中添加所需的数据

public function myOnPostSerializeMethod(ObjectEvent $event)
{
    if (!($event->getObject() instance of YourEntity)) {
         return;
    }

    $timestamp = $event->getObject()->getTimestamp();

    $visitor = $event->getVisitor();
    $visitor->addData('date', $this->formatter->format($timestamp));
}

P.S。我没有检查代码,所以也许我错了某个方法名称,但想法很明确,我希望