Reputation: 331
We use the Symfony Serializer to convert some Doctrine objects to JSON, goal is to provide them as results of API calls.
Out data model has about thirty classes, all are somehow linked with each other and the Doctrine model reflects this. So navigation from one instance to other linked instances is easy.
Now, we are pretty happy that no changes are necessary when we add a new attribute to a class. However, the situation is different is a new link is added, this often adds way too much information because the linked classes also have links and they have links and arrays of objects...
To restrict this, we typically add ignored attributes:
protected function serialize($e, $ignored = ['user'])
{
if ($this->container->has('serializer')) {
$this->serializer = $this->container->get('serializer');
} else {
throw new ServiceNotFoundException('Serializer not found');
}
return $this->serializer->serialize($e, 'json', [
'ignored_attributes' => $ignored,
ObjectNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) {
if (method_exists($object, 'getUuid')) {
return $object->getUuid();
} elseif (method_exists($object, 'getId')) {
return $object->getId();
} elseif (method_exists($object, '__toString')) {
return $object->__toString();
} else {
return '[Reference to object of type ' . get_class($object) . ']';
}
},
]);
}
And then:
return new Response($this->serialize(
[
'presentation' => $presentation,
],
[
'zoomUser',
'userExcelDownloads',
'presentationUserTopics',
'addedBy',
'user',
'presentations',
'sponsorScopes',
'sponsorPresentations',
'showroomScope',
'presentationsForTopic',
'presentationsForTopics',
'presentationHistories',
'showroomTopics',
'presentation',
'presentationHistory',
]
));
This works but maintenance is horrible - when ever the database model is changed, there is the risk that an API call emits a few more MB because a new attribute would have to be ignored. There is no way of finding this.
So how do you handle this?
One solution could be to restrict the serialization depth similar to the CIRCULAR_REFERENCE_HANDLER, i.e., for objects on level three just add the IDs and not the full objects. How could I build this?
Upvotes: 0
Views: 2146
Reputation: 331
We switched to JMS Serializer Bundle where setting the max. depth is very simple and helps us a lot.
https://jmsyst.com/bundles/JMSSerializerBundle
For Symfony serializer, the only way is to use serialization groups.
Upvotes: 0
Reputation: 436
Symfony serializer has built-in Ignore strategy (https://symfony.com/doc/current/components/serializer.html#ignoring-attributes)
you can ignore the attribute directly from the model.
use Symfony\Component\Serializer\Annotation\Ignore;
class Presentation
{
/**
* @Ignore()
*/
public $zoomUser;
//...
}
or by using context.
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$normalizer = new ObjectNormalizer();
$encoder = new JsonEncoder();
$serializer = new Serializer([$normalizer], [$encoder]);
$serializer->serialize($presentation, 'json', [AbstractNormalizer::IGNORED_ATTRIBUTES => ['zoomUser']]);
Upvotes: 0