复杂序列化
Complex serialization
例如,我有两个实体:主(父)实体(例如 User
)和从属实体(Post
)。我想使用 JMS Serializer 序列化 User
实体及其第一个 post 日期的附加信息。存储在数据库中的 post 日期是时间戳 int,但我想用我的助手(只是一个服务)将它序列化,它将 int 转换为具有某种格式的 sting。
尝试使用实体 class 的方法创建 virtual_property
,但未能将我的助手注入实体 class。对我来说解决它的唯一方法是自己序列化到控制器中:
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;
}
注意:这个例子是合成的,在现实世界中我有更复杂的方法,而不仅仅是日期格式化程序。但主要思想是一样的。
我觉得应该有更好的方法来做到这一点。
当然还有更好的办法。它被称为序列化事件。
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。我没有检查代码,所以也许我在某个地方弄错了方法名称,但我希望思路很清楚
Dmtry 的解决方案应该非常适合您的情况。
事件 listener/subscriber 是这种情况下的最佳解决方案。
一个更通用的解决方案,它甚至适用于对象,并将触发 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
被序列化程序忽略...
例如,我有两个实体:主(父)实体(例如 User
)和从属实体(Post
)。我想使用 JMS Serializer 序列化 User
实体及其第一个 post 日期的附加信息。存储在数据库中的 post 日期是时间戳 int,但我想用我的助手(只是一个服务)将它序列化,它将 int 转换为具有某种格式的 sting。
尝试使用实体 class 的方法创建 virtual_property
,但未能将我的助手注入实体 class。对我来说解决它的唯一方法是自己序列化到控制器中:
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;
}
注意:这个例子是合成的,在现实世界中我有更复杂的方法,而不仅仅是日期格式化程序。但主要思想是一样的。
我觉得应该有更好的方法来做到这一点。
当然还有更好的办法。它被称为序列化事件。
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。我没有检查代码,所以也许我在某个地方弄错了方法名称,但我希望思路很清楚
Dmtry 的解决方案应该非常适合您的情况。
事件 listener/subscriber 是这种情况下的最佳解决方案。
一个更通用的解决方案,它甚至适用于对象,并将触发 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
被序列化程序忽略...