I finally found the answer.
First I had to create an event subsciber like this :
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\PreDeserializeEvent;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
class TaskSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
[
'event' => Events::PRE_SERIALIZE,
'format' => 'json',
'class' => 'Task', // fully qualified name here
'method' => 'onPreSerializeTaskJson',
],
[
'event' => Events::PRE_DESERIALIZE,
'format' => 'json',
'class' => 'Task',
'method' => 'onPreDeserializeTaskJson',
]
];
}
public function onPreSerializeTaskJson(PreSerializeEvent $event)
{
/** @var Task $task */
$task = $event->getObject();
$task->setStatus($task->getStatusLabel());
}
public function onPreDeserializeTaskJson(PreDeserializeEvent $event)
{
$data = $event->getData();
$data['status'] = Task::getStatusFromLabel($data['status']);
$event->setData($data);
}
}
What I'm doing here :
- Before serialization, I set the status value of my Task object with the label
- Before deserialization, I change the value of the serialized object from the label to the raw integer value
For this solution, field has to be exposed (expose: true
or @Expose
) to the serializer.
Then I declared the subscriber as a service in Symfony with the tag jms_serializer.event_subscriber
.
serializer.subscriber.task:
class: %serializer.subscriber.task.class% # TaskSubscriber class path
tags:
- { name: jms_serializer.event_subscriber }
And it works.
It's the best way I found to both serialize and deserialize. It's also possible to manipulate data on post_serialize and post_deserialize events. For example, add a new field on a serialized object :
use JMS\Serializer\EventDispatcher\ObjectEvent;
public function onPostSerializeTaskJson(ObjectEvent $event)
{
/** @var Task $task */
$task = $event->getObject();
$event->getVisitor()->addData('nb_related', count($task->getRelatedTasks()));
}