Skip to content

Commit ad209b4

Browse files
committed
feature #61563 [Serializer] Add #[ExtendsSerializationFor] to declare new serialization attributes for a class (nicolas-grekas)
This PR was merged into the 7.4 branch. Discussion ---------- [Serializer] Add `#[ExtendsSerializationFor]` to declare new serialization attributes for a class | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | - | License | MIT This PR builds on #61532 It's a sibling of #61545 I propose to add a `#[ExtendsSerializationFor]` attribute that allows adding serialization attributes to another class. This is typically needed for third party classes. For context, Sylius has a nice doc about this: https://docs.sylius.com/the-customization-guide/customizing-serialization-of-api At the moment, the only way to achieve this is by declaring the new attributes in the (hardcoded) `config/serialization/` folder, using either xml or yaml. No attributes. With this PR, one will be able to define those extra serialization attributes using PHP attributes, set on classes that'd mirror the properties/getters of the targeted class. The compiler pass will ensure that all properties/getters declared in these source classes also exist in the target class. (source = the app's class that declares the new serialization attributes; target = the existing class to add serialization attributes to.) ```php #[ExtendsSerializationFor(TargetClass::class)] abstract class SourceClass { #[Groups(['my_app'])] #[SerializedName('fullName')] public string $name = ''; #[Groups(['my_app'])] public string $email = ''; #[Groups(['my_app'])] #[MaxDepth(2)] public Category $category; } ``` (I made the class abstract because it's not supposed to be instantiated - but it's not mandatory.) Here are the basics of how this works: 1. During container compilation, classes marked with `#[ExtendsSerializationFor(Target::class)]` are collected and validated: the container checks that members declared on the source exist on the target. If not, a `MappingException` is thrown. 2. The serializer is configured to map the target to its source classes. 3. At runtime, when loading serialization metadata for the target, attributes (groups, serialized names, max depth, etc.) are read from both the target and its mapped source classes and applied accordingly. Commits ------- 386f949a41a [Serializer] Add `#[ExtendsSerializationFor]` to declare new serialization attributes for a class
2 parents f9abefa + 7750b35 commit ad209b4

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

DependencyInjection/FrameworkExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@
189189
use Symfony\Component\Semaphore\SemaphoreFactory;
190190
use Symfony\Component\Semaphore\Store\StoreFactory as SemaphoreStoreFactory;
191191
use Symfony\Component\Serializer\Attribute as SerializerMapping;
192+
use Symfony\Component\Serializer\Attribute\ExtendsSerializationFor;
192193
use Symfony\Component\Serializer\DependencyInjection\AttributeMetadataPass as SerializerAttributeMetadataPass;
193194
use Symfony\Component\Serializer\Encoder\DecoderInterface;
194195
use Symfony\Component\Serializer\Encoder\EncoderInterface;
@@ -2172,6 +2173,11 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
21722173
$container->getDefinition('serializer.normalizer.property')->setArgument(5, $defaultContext);
21732174

21742175
$container->setParameter('.serializer.named_serializers', $config['named_serializers'] ?? []);
2176+
2177+
$container->registerAttributeForAutoconfiguration(ExtendsSerializationFor::class, function (ChildDefinition $definition, ExtendsSerializationFor $attribute) {
2178+
$definition->addTag('serializer.attribute_metadata', ['for' => $attribute->class])
2179+
->addTag('container.excluded', ['source' => 'because it\'s a serializer metadata extension']);
2180+
});
21752181
}
21762182

21772183
private function registerJsonStreamerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void

0 commit comments

Comments
 (0)