Symfony 复杂序列化

Symfony 复杂序列化,symfony,jmsserializerbundle,jms-serializer,Symfony,Jmsserializerbundle,Jms Serializer,例如,我有两个实体:主(父)实体(例如User)和从属实体(Post)。我想使用JMS序列化程序对User实体进行序列化,并提供其第一次发布日期的附加信息。DB中存储的post日期是timestamp int,但我想用我的助手(只是一个服务)将其序列化,该助手将int转换为带有一些格式的sting 尝试在实体类中使用方法创建虚拟属性,但未能将我的助手插入实体类。对我来说,解决这个问题的唯一方法是自己序列化到控制器中: public function someAction() { $ser

例如,我有两个实体:主(父)实体(例如
User
)和从属实体(
Post
)。我想使用JMS序列化程序对
User
实体进行序列化,并提供其第一次发布日期的附加信息。DB中存储的post日期是timestamp int,但我想用我的助手(只是一个服务)将其序列化,该助手将int转换为带有一些格式的sting

尝试在实体类中使用方法创建
虚拟属性
,但未能将我的助手插入实体类。对我来说,解决这个问题的唯一方法是自己序列化到控制器中:

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;
}
注意:这个例子是合成的,在现实世界中,我有更复杂的方法,而不仅仅是日期格式化程序。但主要思想是一样的


我觉得应该有更好的方法来做这件事。

当然,有更好的方法。这叫做序列化事件

您可以创建事件订阅服务器

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

另外,我没有检查代码,所以可能我在方法的名称上弄错了,但是想法很清楚,我希望有更好的方法。这叫做序列化事件

您可以创建事件订阅服务器

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

另外,我没有检查代码,所以可能我在方法名称方面弄错了,但是想法很清楚,我希望Dmtry的解决方案能够完美地适用于您的情况

在这种情况下,事件侦听器/订阅服务器是最好的解决方案

更通用的解决方案是,它甚至可以处理对象,并将触发JMS序列化程序的整个事件系统部分(Dmtry的解决方案仅适用于原语,仅适用于JSON/YAML,而不适用于XML):

类MyFormatter实现EventSubscriberInterface
{
公共静态函数getSubscribedEvents()
{
返回数组(
排列(
'事件'=>'序列化程序。后序列化',
'方法'=>'onPostSerialize',
“类”=>“您的实体”
),
);
}
公共函数构造(MyFormatter$FoerFormatter)
{
$this->formatter=$formatter;
}
公共函数onPostSerialize(ObjectEvent$event)
{
$visitor=$event->getVisitor();
$context=$event->getContext();
$timestamp=$event->getObject()->getTimestamp();
$formattedTime=$this->formatter->format($timestamp);
$metadata=新的StaticPropertyMetadata('stdClass','first\u post\u date',$formattedTime);
$visitor->visitProperty($metadata、$formattedTime、$context);
}
}

stdClass
被序列化程序忽略…

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

在这种情况下,事件侦听器/订阅服务器是最好的解决方案

更通用的解决方案是,它甚至可以处理对象,并将触发JMS序列化程序的整个事件系统部分(Dmtry的解决方案仅适用于原语,仅适用于JSON/YAML,而不适用于XML):

类MyFormatter实现EventSubscriberInterface
{
公共静态函数getSubscribedEvents()
{
返回数组(
排列(
'事件'=>'序列化程序。后序列化',
'方法'=>'onPostSerialize',
“类”=>“您的实体”
),
);
}
公共函数构造(MyFormatter$FoerFormatter)
{
$this->formatter=$formatter;
}
公共函数onPostSerialize(ObjectEvent$event)
{
$visitor=$event->getVisitor();
$context=$event->getContext();
$timestamp=$event->getObject()->getTimestamp();
$formattedTime=$this->formatter->format($timestamp);
$metadata=新的StaticPropertyMetadata('stdClass','first\u post\u date',$formattedTime);
$visitor->visitProperty($metadata、$formattedTime、$context);
}
}

stdClass
被序列化程序忽略…

我考虑了事件,但是这个事件会在每次序列化时触发吗?如果我有几个实体,我想填充它们,那么代码将有很多
If($event->getObject()SomeEntity实例){$this->someEntityFormat($event);}
我考虑过事件,但是每次序列化都会触发这个事件吗?如果我有几个要填充的实体,那么代码将有很多
If($event->getObject()SomeEntity实例){$this->someEntityFormat($event);}