Search code examples
symfonyjmsserializerbundlejms-serializer

Complex serialization


For example, I have two entities: main (parent) entity (for example User) and dependent entity (Post). I want to serialize User entity using JMS Serializer with additional information of its first post date. The post date stored in DB is timestamp int, but I want to serialize it with my helper (just a service) which converts int to sting with some formatting.

Trying to create a virtual_property with method at entity class, but failed to inject my helper into entity class. The only way to solve it for me is to serialize by myself into controller:

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

NB: this example is synthetic, in the real world I have more complex methods, not just date formatter. But the main idea is the same.

I feel there should be better way to do this.


Solution

  • Dmtry's solution should work perfectly for your case.

    An event listener/subscriber is the best solution in this case.

    A bit more general solution, that works even with objects and will trigger the whole event system part of the JMS serializer (Dmtry's solution works only with primitives and only for JSON/YAML, not XML), is:

    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 is ignored by the serializer...