In Symfony 7.2, the Serializer component allows configuring multiple serializer instances with different default contexts, name converters, and sets of normalizers and encoders. This is useful, for example, when your application communicates with multiple APIs, each using different rules.
First, use the new named_serializers
option to define the different serializers
and their contexts:
1 2 3 4 5 6 7 8 9 10
# config/packages/serializer.yaml
serializer:
named_serializers:
api_client1:
name_converter: 'serializer.name_converter.camel_case_to_snake_case'
default_context:
enable_max_depth: true
api_client2:
default_context:
enable_max_depth: false
Now you can inject the different serializers using named aliases including the Target attribute:
1 2 3 4 5 6 7 8 9 10 11 12
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(
SerializerInterface $serializer, // Default serializer
SerializerInterface $apiClient1Serializer, // api_client1 serializer
#[Target('apiClient2.serializer')] // api_client2 serializer
SerializerInterface $someName,
) {
// ...
}
}
If you define custom normalizers, you can apply them only to certain serializers
thanks to the serializer
tag attribute (if you don't set this attribute, the
normalizer will be applied only to the default
serializer):
1 2 3 4 5 6 7 8 9 10
get_set_method_normalizer:
class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
autoconfigure: false # this is needed so it's not included in the default serializer
tags:
# single serializer
- serializer.normalizer: { serializer: 'api_client1' }
# or multiple ones
- serializer.normalizer: { serializer: [ 'api_client1', 'api_client2' ] }
# use * to include the service in all serializers, including the default one
- serializer.normalizer: { serializer: '*' }
Lastly, since Symfony comes with some built-in normalizers and encoders, there are new options to exclude those in case you don't want to use them:
1 2 3 4 5 6
serializer:
named_serializers:
api_client1:
include_built_in_normalizers: false
include_built_in_encoders: true
# ...
Shouldn't it be "SerializerInterface $apiClient1Serializer" instead of "SerializerInterface $api1ClientSerializer" ?
You are right Nicolas. I just fixed that. Thanks.
And if you make custom normalizer with the NormalizerAware Interface/Trait to customize behaviour, can that be enabled/disabled on certain named serializers?
(It wouldn't be the first time that I encounter issues with how the serializer behaves in API Platform projects because of the API-platform config, this would be awesome to have a 'clean' instance ready for use inside of API Platform state processors / providers... although with a new Mapper component coming that might not be needed anymore).
If you make a
*Aware
normalizer, you need to register different services for each serializer instead of registering the same normalizer service inside multiple normalizers (a single service instance cannot be aware of multiple serializers as eachset*
call overrides the previous one)Waw
Coool !