From 18b84194424511fe541fc7962553ae423e4553c7 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Fri, 31 May 2024 18:43:25 +0200 Subject: [PATCH 1/2] [FrameworkBundle] Fix setting default context for certain normalizers --- DependencyInjection/FrameworkExtension.php | 8 ++- Resources/config/serializer.php | 1 - Tests/Functional/AbstractWebTestCase.php | 2 +- Tests/Functional/SerializerTest.php | 70 ++++++++++++------- Tests/Functional/app/AppKernel.php | 5 ++ Tests/Functional/app/Serializer/config.yml | 45 ------------ .../app/Serializer/default_context.yaml | 59 ++++++++++++++++ 7 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 Tests/Functional/app/Serializer/default_context.yaml diff --git a/DependencyInjection/FrameworkExtension.php b/DependencyInjection/FrameworkExtension.php index ebaed7c2b..71505f251 100644 --- a/DependencyInjection/FrameworkExtension.php +++ b/DependencyInjection/FrameworkExtension.php @@ -1859,18 +1859,20 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder } $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments(); - $context = []; + $context = $arguments[6] ?? $defaultContext; if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) { - $context += ($arguments[6] ?? $defaultContext) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])]; + $context += ['circular_reference_handler' => new Reference($config['circular_reference_handler'])]; $container->getDefinition('serializer.normalizer.object')->setArgument(5, null); } if ($config['max_depth_handler'] ?? false) { - $context += ($arguments[6] ?? $defaultContext) + ['max_depth_handler' => new Reference($config['max_depth_handler'])]; + $context += ['max_depth_handler' => new Reference($config['max_depth_handler'])]; } $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context); + + $container->getDefinition('serializer.normalizer.property')->setArgument(5, $defaultContext); } private function registerPropertyInfoConfiguration(ContainerBuilder $container, PhpFileLoader $loader) diff --git a/Resources/config/serializer.php b/Resources/config/serializer.php index 7762e5a64..2fb42027f 100644 --- a/Resources/config/serializer.php +++ b/Resources/config/serializer.php @@ -139,7 +139,6 @@ service('property_info')->ignoreOnInvalid(), service('serializer.mapping.class_discriminator_resolver')->ignoreOnInvalid(), null, - [], ]) ->alias(PropertyNormalizer::class, 'serializer.normalizer.property') diff --git a/Tests/Functional/AbstractWebTestCase.php b/Tests/Functional/AbstractWebTestCase.php index bce53b866..30ca91d1e 100644 --- a/Tests/Functional/AbstractWebTestCase.php +++ b/Tests/Functional/AbstractWebTestCase.php @@ -52,7 +52,7 @@ protected static function getKernelClass(): string protected static function createKernel(array $options = []): KernelInterface { - $class = self::getKernelClass(); + $class = static::getKernelClass(); if (!isset($options['test_case'])) { throw new \InvalidArgumentException('The option "test_case" must be set.'); diff --git a/Tests/Functional/SerializerTest.php b/Tests/Functional/SerializerTest.php index 9a6527b14..7ce9b0735 100644 --- a/Tests/Functional/SerializerTest.php +++ b/Tests/Functional/SerializerTest.php @@ -11,6 +11,10 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\AppKernel; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + /** * @author Kévin Dunglas */ @@ -33,39 +37,55 @@ public function testDeserializeArrayOfObject() $this->assertEquals($expected, $result); } - /** - * @dataProvider provideNormalizersAndEncodersWithDefaultContextOption - */ - public function testNormalizersAndEncodersUseDefaultContextConfigOption(string $normalizerId) + public function testNormalizersAndEncodersUseDefaultContextConfigOption() { - static::bootKernel(['test_case' => 'Serializer']); + /** @var SerializerKernel $kernel */ + $kernel = static::bootKernel(['test_case' => 'Serializer', 'root_config' => 'default_context.yaml']); + + foreach ($kernel->normalizersAndEncoders as $normalizerOrEncoderId) { + $normalizerOrEncoder = static::getContainer()->get($normalizerOrEncoderId); - $normalizer = static::getContainer()->get($normalizerId); + $reflectionObject = new \ReflectionObject($normalizerOrEncoder); + $property = $reflectionObject->getProperty('defaultContext'); + $property->setAccessible(true); - $reflectionObject = new \ReflectionObject($normalizer); - $property = $reflectionObject->getProperty('defaultContext'); - $property->setAccessible(true); + $defaultContext = $property->getValue($normalizerOrEncoder); - $defaultContext = $property->getValue($normalizer); + self::assertArrayHasKey('fake_context_option', $defaultContext); + self::assertEquals('foo', $defaultContext['fake_context_option']); + } + } - self::assertArrayHasKey('fake_context_option', $defaultContext); - self::assertEquals('foo', $defaultContext['fake_context_option']); + protected static function getKernelClass(): string + { + return SerializerKernel::class; } +} + +class SerializerKernel extends AppKernel implements CompilerPassInterface +{ + public $normalizersAndEncoders = [ + 'serializer.normalizer.property.alias', // Special case as this normalizer isn't tagged + ]; - public static function provideNormalizersAndEncodersWithDefaultContextOption(): array + public function process(ContainerBuilder $container) { - return [ - ['serializer.normalizer.constraint_violation_list.alias'], - ['serializer.normalizer.dateinterval.alias'], - ['serializer.normalizer.datetime.alias'], - ['serializer.normalizer.json_serializable.alias'], - ['serializer.normalizer.problem.alias'], - ['serializer.normalizer.uid.alias'], - ['serializer.normalizer.object.alias'], - ['serializer.encoder.xml.alias'], - ['serializer.encoder.yaml.alias'], - ['serializer.encoder.csv.alias'], - ]; + $services = array_merge( + $container->findTaggedServiceIds('serializer.normalizer'), + $container->findTaggedServiceIds('serializer.encoder') + ); + foreach ($services as $serviceId => $attributes) { + $class = $container->getDefinition($serviceId)->getClass(); + if (null === $reflectionConstructor = (new \ReflectionClass($class))->getConstructor()) { + continue; + } + foreach ($reflectionConstructor->getParameters() as $reflectionParam) { + if ('array $defaultContext' === $reflectionParam->getType()->getName().' $'.$reflectionParam->getName()) { + $this->normalizersAndEncoders[] = $serviceId.'.alias'; + break; + } + } + } } } diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php index 49fb0ca2e..0c3c9cc35 100644 --- a/Tests/Functional/app/AppKernel.php +++ b/Tests/Functional/app/AppKernel.php @@ -49,6 +49,11 @@ public function __construct($varDir, $testCase, $rootConfig, $environment, $debu parent::__construct($environment, $debug); } + protected function getContainerClass(): string + { + return parent::getContainerClass().substr(md5($this->rootConfig), -16); + } + public function registerBundles(): iterable { if (!file_exists($filename = $this->getProjectDir().'/'.$this->testCase.'/bundles.php')) { diff --git a/Tests/Functional/app/Serializer/config.yml b/Tests/Functional/app/Serializer/config.yml index f023f6341..c22edfcce 100644 --- a/Tests/Functional/app/Serializer/config.yml +++ b/Tests/Functional/app/Serializer/config.yml @@ -8,7 +8,6 @@ framework: max_depth_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler default_context: enable_max_depth: true - fake_context_option: foo property_info: { enabled: true } services: @@ -16,50 +15,6 @@ services: alias: serializer public: true - serializer.normalizer.constraint_violation_list.alias: - alias: serializer.normalizer.constraint_violation_list - public: true - - serializer.normalizer.dateinterval.alias: - alias: serializer.normalizer.dateinterval - public: true - - serializer.normalizer.datetime.alias: - alias: serializer.normalizer.datetime - public: true - - serializer.normalizer.json_serializable.alias: - alias: serializer.normalizer.json_serializable - public: true - - serializer.normalizer.problem.alias: - alias: serializer.normalizer.problem - public: true - - serializer.normalizer.uid.alias: - alias: serializer.normalizer.uid - public: true - - serializer.normalizer.property.alias: - alias: serializer.normalizer.property - public: true - - serializer.normalizer.object.alias: - alias: serializer.normalizer.object - public: true - - serializer.encoder.xml.alias: - alias: serializer.encoder.xml - public: true - - serializer.encoder.yaml.alias: - alias: serializer.encoder.yaml - public: true - - serializer.encoder.csv.alias: - alias: serializer.encoder.csv - public: true - Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler: ~ Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler: ~ diff --git a/Tests/Functional/app/Serializer/default_context.yaml b/Tests/Functional/app/Serializer/default_context.yaml new file mode 100644 index 000000000..de6114c5d --- /dev/null +++ b/Tests/Functional/app/Serializer/default_context.yaml @@ -0,0 +1,59 @@ +imports: + - { resource: ../config/default.yml } + +framework: + serializer: + enabled: true + circular_reference_handler: ~ # This must be null + max_depth_handler: ~ # This must be null + default_context: + fake_context_option: foo + +services: + serializer.normalizer.constraint_violation_list.alias: + alias: serializer.normalizer.constraint_violation_list + public: true + + serializer.normalizer.dateinterval.alias: + alias: serializer.normalizer.dateinterval + public: true + + serializer.normalizer.datetime.alias: + alias: serializer.normalizer.datetime + public: true + + serializer.normalizer.json_serializable.alias: + alias: serializer.normalizer.json_serializable + public: true + + serializer.normalizer.object.alias: + alias: serializer.normalizer.object + public: true + + serializer.normalizer.problem.alias: + alias: serializer.normalizer.problem + public: true + + serializer.normalizer.property.alias: + alias: serializer.normalizer.property + public: true + + serializer.normalizer.uid.alias: + alias: serializer.normalizer.uid + public: true + + serializer.encoder.csv.alias: + alias: serializer.encoder.csv + public: true + + serializer.encoder.json.alias: + alias: serializer.encoder.json + public: true + + serializer.encoder.xml.alias: + alias: serializer.encoder.xml + public: true + + serializer.encoder.yaml.alias: + alias: serializer.encoder.yaml + public: true From b3a0478da350dacaade8c3249682a57685045aac Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 22 Jun 2024 13:31:15 +0200 Subject: [PATCH 2/2] fix tests --- Tests/Functional/SerializerTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Tests/Functional/SerializerTest.php b/Tests/Functional/SerializerTest.php index 49019ab2a..9d75c5bf6 100644 --- a/Tests/Functional/SerializerTest.php +++ b/Tests/Functional/SerializerTest.php @@ -44,6 +44,10 @@ public function testNormalizersAndEncodersUseDefaultContextConfigOption() $kernel = static::bootKernel(['test_case' => 'Serializer', 'root_config' => 'default_context.yaml']); foreach ($kernel->normalizersAndEncoders as $normalizerOrEncoderId) { + if (!static::getContainer()->has($normalizerOrEncoderId)) { + continue; + } + $normalizerOrEncoder = static::getContainer()->get($normalizerOrEncoderId); $reflectionObject = new \ReflectionObject($normalizerOrEncoder); @@ -68,7 +72,7 @@ class SerializerKernel extends AppKernel implements CompilerPassInterface 'serializer.normalizer.property.alias', // Special case as this normalizer isn't tagged ]; - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { $services = array_merge( $container->findTaggedServiceIds('serializer.normalizer'),