Symfony v4.2
I'm trying to use symfony's normalizer and serialiser to convert my entities into JSON.
I followed the Groups annotation pattern, because it sounds like the most intuitive and future proof way to do it.
According to the docs, we have to manually instantiate the ClassMetadataFactory
in order to load the AnnotationLoader
. I'm still using the ObjectNormalizer
which worked fine before using annotations.
Here's my serialize method:
/**
* @param bool $event Serialize all event fields (except references)
* @param bool $meta Serialize referenced meta instance
* @param bool $targets Serialize referenced target instances
* @param bool $users Serialize referenced user instances
* @param bool $videos Serialize referenced video instances
* @param bool $photos Serialize referenced photo instances
* @return string
*/
public function serialize($event = true, $meta = false, $targets = false, $users = false, $videos = false, $photos = false) {
$serializingGroups = [];
if ($event) {
$serializingGroups[] = 'event';
}
if ($meta) {
$serializingGroups[] = 'meta';
}
if ($targets) {
$serializingGroups[] = "targets";
}
if ($users) {
$serializingGroups[] = 'users';
}
if ($videos) {
$serializingGroups[] = 'videos';
}
if ($photos) {
$serializingGroups[] = 'photos';
}
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([$normalizer], [new JsonEncoder()]);
$data = $serializer->normalize($this, null, ['groups' => $serializingGroups]);
return $serializer->serialize($data, 'json');
}
These groups are there to speed up serialization if I don't need associations te be serialized.
Now that I use group annotations, the json looks like this
{
"id":2,
"title":"test",
"description":"<p> test<\/p>",
"subscriptionPrice":"0.00",
"subscriptionUntil":[], // DATE - WHY EMPTY ARRAY?
"start":[], // DATE - WHY EMPTY ARRAY?
"end":[], // DATE - WHY EMPTY ARRAY?
"allDay":false,
"creationDate":[], // DATE - WHY EMPTY ARRAY?
"editDate":[], // DATE - WHY EMPTY ARRAY?
"editable":true,
"startEditable":true,
"durationEditable":true,
"overlap":false,
"color":"#9EABAB",
"backgroundColor":"#9eabab",
"borderColor":"#9eabab",
"textColor":"#000000",
"isRecurring":true,
"meta":[], // ASSOCIATED ENTITY - WHY EMPTY ARRAY?
"targets":[[]] // ASSOCIATED COLLECTION OF ENTITIES - WHY EMPTY ARRAY?
}
Why does it work when I don't use annotations? Why are dates and other entities empty arrays when I do use annotations?
Eureca!
Here is a code snippet from my serialize method:
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$serializer = new Serializer([
// Add a Datetimenormalizer as the first normalizer in the list
new DatetimeNormalizer(),
$normalizer
], [new JsonEncoder()]);
return $serializer->serialize($this, 'json', [
// $serializer->addCircularReferenceHandler() IS DEPRECATED
// define the handler like this:
ObjectNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($event) {
return '/event/'.$event->id;
}
,ObjectNormalizer::GROUPS => $serializingGroups
]);
First of all, the reason why meta
and targets
weren't serializing was because I had the wrong import in my Meta
and Target
entities. Make sure it is: use Symfony\Component\Serializer\Annotation\Groups;
... so... yeah... moving on.
The dates did serialize when I commented out //,ObjectNormalizer::GROUPS => $serializingGroups
. So why don't they serialize when groups aren't commented out?
My guess is that the DateTime
class doesn't have the Groups
annotations, so the normalizer was never able to get any of the DateTime
attributes
This is solved by adding a DatetimeNormalizer
as the first normalizer in the array: $serializer = new Serializer([new DatetimeNormalizer(),$normalizer])
This is how my entities serialize correctly :D