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.