Skip to content

Commit 8c3e9c1

Browse files
[Serializer] Allow using attributes to declare compile-time serialization metadata
1 parent b0f0bdf commit 8c3e9c1

File tree

18 files changed

+215
-22
lines changed

18 files changed

+215
-22
lines changed

UPGRADE-7.4.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Serializer
9393
* Make `AttributeMetadata` and `ClassMetadata` final
9494
* Deprecate class aliases in the `Annotation` namespace, use attributes instead
9595
* Deprecate getters in attribute classes in favor of public properties
96+
* Deprecate `ClassMetadataFactoryCompiler`
9697

9798
String
9899
------

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/SerializerCacheWarmer.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1515
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
1616
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
17+
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
1718
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
1819
use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
1920
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
2021
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
2122

2223
/**
23-
* Warms up XML and YAML serializer metadata.
24+
* Warms up serializer metadata.
2425
*
2526
* @author Titouan Galopin <galopintitouan@gmail.com>
2627
*
@@ -66,14 +67,14 @@ protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, ?strin
6667
/**
6768
* @param LoaderInterface[] $loaders
6869
*
69-
* @return XmlFileLoader[]|YamlFileLoader[]
70+
* @return list<XmlFileLoader|YamlFileLoader|AttributeLoader>
7071
*/
7172
private function extractSupportedLoaders(array $loaders): array
7273
{
7374
$supportedLoaders = [];
7475

7576
foreach ($loaders as $loader) {
76-
if ($loader instanceof XmlFileLoader || $loader instanceof YamlFileLoader) {
77+
if (method_exists($loader, 'getMappedClasses')) {
7778
$supportedLoaders[] = $loader;
7879
} elseif ($loader instanceof LoaderChain) {
7980
$supportedLoaders = array_merge($supportedLoaders, $this->extractSupportedLoaders($loader->getLoaders()));

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,9 @@
186186
use Symfony\Component\Semaphore\Semaphore;
187187
use Symfony\Component\Semaphore\SemaphoreFactory;
188188
use Symfony\Component\Semaphore\Store\StoreFactory as SemaphoreStoreFactory;
189+
use Symfony\Component\Serializer\DependencyInjection\AttributeMetadataPass as SerializerAttributeMetadataPass;
189190
use Symfony\Component\Serializer\Encoder\DecoderInterface;
190191
use Symfony\Component\Serializer\Encoder\EncoderInterface;
191-
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
192192
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
193193
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
194194
use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;
@@ -2055,10 +2055,15 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
20552055
}
20562056

20572057
$serializerLoaders = [];
2058-
if (isset($config['enable_attributes']) && $config['enable_attributes']) {
2059-
$attributeLoader = new Definition(AttributeLoader::class);
20602058

2061-
$serializerLoaders[] = $attributeLoader;
2059+
if (($config['enable_attributes'] ?? false) || class_exists(SerializerAttributeMetadataPass::class)) {
2060+
$serializerLoaders[] = new Reference('serializer.mapping.attribute_loader');
2061+
2062+
$container->getDefinition('serializer.mapping.attribute_loader')
2063+
->replaceArgument(0, $config['enable_attributes'] ?? false);
2064+
} else {
2065+
// BC with symfony/serializer < 7.4
2066+
$container->removeDefinition('serializer.mapping.attribute_services_loader');
20622067
}
20632068

20642069
$fileRecorder = function ($extension, $path) use (&$serializerLoaders) {
@@ -2095,7 +2100,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
20952100
$chainLoader->replaceArgument(0, $serializerLoaders);
20962101
$container->getDefinition('serializer.mapping.cache_warmer')->replaceArgument(0, $serializerLoaders);
20972102

2098-
if (isset($config['name_converter']) && $config['name_converter']) {
2103+
if ($config['name_converter'] ?? false) {
20992104
$container->setParameter('.serializer.name_converter', $config['name_converter']);
21002105
$container->getDefinition('serializer.name_converter.metadata_aware')->setArgument(1, new Reference($config['name_converter']));
21012106
}

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass;
6666
use Symfony\Component\Runtime\SymfonyRuntime;
6767
use Symfony\Component\Scheduler\DependencyInjection\AddScheduleMessengerPass;
68+
use Symfony\Component\Serializer\DependencyInjection\AttributeMetadataPass as SerializerAttributeMetadataPass;
6869
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
6970
use Symfony\Component\Translation\DependencyInjection\DataCollectorTranslatorPass;
7071
use Symfony\Component\Translation\DependencyInjection\LoggingTranslatorPass;
@@ -168,6 +169,7 @@ public function build(ContainerBuilder $container): void
168169
$this->addCompilerPassIfExists($container, TranslationDumperPass::class);
169170
$container->addCompilerPass(new FragmentRendererPass());
170171
$this->addCompilerPassIfExists($container, SerializerPass::class);
172+
$this->addCompilerPassIfExists($container, SerializerAttributeMetadataPass::class);
171173
$this->addCompilerPassIfExists($container, PropertyInfoPass::class);
172174
$this->addCompilerPassIfExists($container, PropertyInfoConstructorPass::class);
173175
$container->addCompilerPass(new ControllerArgumentValueResolverPass());

src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
2929
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
3030
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
31+
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
3132
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
3233
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
3334
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
@@ -151,6 +152,9 @@
151152
->set('serializer.mapping.chain_loader', LoaderChain::class)
152153
->args([[]])
153154

155+
->set('serializer.mapping.attribute_loader', AttributeLoader::class)
156+
->args([true, []])
157+
154158
// Class Metadata Factory
155159
->set('serializer.mapping.class_metadata_factory', ClassMetadataFactory::class)
156160
->args([service('serializer.mapping.chain_loader')])

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_mapping_without_annotations.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'handle_all_throwables' => true,
77
'php_errors' => ['log' => true],
88
'serializer' => [
9-
'enable_attributes' => false,
9+
'enable_attributes' => true,
1010
'mapping' => [
1111
'paths' => [
1212
'%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files',

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_mapping_without_annotations.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<framework:config http-method-override="false" handle-all-throwables="true">
88
<framework:annotations enabled="false" />
99
<framework:php-errors log="true" />
10-
<framework:serializer enable-attributes="false">
10+
<framework:serializer enable-attributes="true">
1111
<framework:mapping>
1212
<framework:path>%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files</framework:path>
1313
<framework:path>%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/serialization.yml</framework:path>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_mapping_without_annotations.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ framework:
55
php_errors:
66
log: true
77
serializer:
8-
enable_attributes: false
8+
enable_attributes: true
99
mapping:
1010
paths:
1111
- "%kernel.project_dir%/Fixtures/TestBundle/Resources/config/serializer_mapping/files"

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
use Symfony\Component\PropertyAccess\PropertyAccessor;
7878
use Symfony\Component\Security\Core\AuthenticationEvents;
7979
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
80-
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
8180
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
8281
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
8382
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
@@ -1563,7 +1562,7 @@ public function testSerializerEnabled()
15631562
$argument = $container->getDefinition('serializer.mapping.chain_loader')->getArgument(0);
15641563

15651564
$this->assertCount(2, $argument);
1566-
$this->assertEquals(AttributeLoader::class, $argument[0]->getClass());
1565+
$this->assertEquals(new Reference('serializer.mapping.attribute_loader'), $argument[0]);
15671566
$this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.name_converter.metadata_aware')->getArgument(1));
15681567
$this->assertEquals(new Reference('property_info', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), $container->getDefinition('serializer.normalizer.object')->getArgument(3));
15691568
}
@@ -1753,6 +1752,7 @@ public function testSerializerMapping()
17531752
$projectDir = $container->getParameter('kernel.project_dir');
17541753
$configDir = __DIR__.'/Fixtures/TestBundle/Resources/config';
17551754
$expectedLoaders = [
1755+
new Reference('serializer.mapping.attribute_loader'),
17561756
new Definition(XmlFileLoader::class, [$configDir.'/serialization.xml']),
17571757
new Definition(YamlFileLoader::class, [$configDir.'/serialization.yml']),
17581758
new Definition(YamlFileLoader::class, [$projectDir.'/config/serializer/foo.yml']),
@@ -1762,15 +1762,15 @@ public function testSerializerMapping()
17621762
new Definition(YamlFileLoader::class, [$configDir.'/serializer_mapping/serialization.yaml']),
17631763
];
17641764

1765-
foreach ($expectedLoaders as $definition) {
1766-
if (is_file($arg = $definition->getArgument(0))) {
1767-
$definition->replaceArgument(0, strtr($arg, '/', \DIRECTORY_SEPARATOR));
1765+
foreach ($expectedLoaders as $loader) {
1766+
if ($loader instanceof Definition && is_file($arg = $loader->getArgument(0))) {
1767+
$loader->replaceArgument(0, strtr($arg, '/', \DIRECTORY_SEPARATOR));
17681768
}
17691769
}
17701770

17711771
$loaders = $container->getDefinition('serializer.mapping.chain_loader')->getArgument(0);
17721772
foreach ($loaders as $loader) {
1773-
if (is_file($arg = $loader->getArgument(0))) {
1773+
if ($loader instanceof Definition && is_file($arg = $loader->getArgument(0))) {
17741774
$loader->replaceArgument(0, strtr($arg, '/', \DIRECTORY_SEPARATOR));
17751775
}
17761776
}

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ CHANGELOG
44
7.4
55
---
66

7+
* Add `AttributeMetadataPass` to declare compile-time constraint metadata using attributes
78
* Add `CDATA_WRAPPING_NAME_PATTERN` support to `XmlEncoder`
89
* Add support for `can*()` methods to `AttributeLoader`
910
* Make `AttributeMetadata` and `ClassMetadata` final
1011
* Deprecate class aliases in the `Annotation` namespace, use attributes instead
1112
* Deprecate getters in attribute classes in favor of public properties
13+
* Deprecate `ClassMetadataFactoryCompiler`
1214

1315
7.3
1416
---

0 commit comments

Comments
 (0)