Teaching jms/serializer to deserialize YAML

I recently was tasked to write an exporter and importer for our project data at work. Luckily enough, jms/serializer makes this rather easy. Although I was only required to support XML, I opted to let the user choose between any of the formats that jms/serializer supports.

After confirming that the process was working fine when using XML or JSON I quickly moved on, knowing that, while jms/serializer is able to serialize to YAML, it offers no support for deserializing YAML. As I am a huge fan of YAML this had always saddened me a little, but I considered adding the support too complex, so I didn’t pursue the idea any further.

Shortly after I came around to, for the first time ever, have a real look at jms/serializer and try and understand its’ inner workings. This was when I decided it was finally time for me to try and add support for deserializing YAML. I coded up the simplest solution that came to my mind:

use JMS\Serializer\GenericDeserializationVisitor;
use Symfony\Component\Yaml\Yaml;

class YamlDeserializationVisitor extends GenericDeserializationVisitor
{
    public function decode($data)
    {
        $yaml = new Yaml();
        return $yaml->parse($data);
    }
}

Surprisingly, those two lines of code were all it took to enable jms/serializer to deserialize YAML. Or so I thought.

jms/serializer also allows you to define custom handlers for specific types, one of which I encountered as I tried to deserialize an instance of \DateTime.

class DateHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = array();

        foreach (array('json', 'xml', 'yml') as $format) {
            $methods[] = array(
                'type' => 'DateTime',
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                'format' => $format,
            );

            // ...
        }

        return $methods;
    }

    public function deserializeDateTimeFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
    {
        // ...
    }

    public function deserializeDateTimeFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
    {
        // ...
    }

    // ...
}

The problem here is, that getSubscribingMethods() does not specify which methods to call: The method names are generated by HandlerRegistry::getDefaultMethod().

All you have to do is create a custom handler, that will handle deserializing \DateTime from YAML, which will get called instead.

Luckily for you, I already took care of that for you and made it into a composer package. There also is a different package if you’re using Symfony2 and want to add YAML deserialization to the jms_serializer service. You can find the packages on packagist.org: ppokatilo/jms-deyaml and jms-deyaml-bundle.