From db412feacccecede724d1075b3809bf0cbdfb710 Mon Sep 17 00:00:00 2001 From: Cornel Cruceru Date: Fri, 12 Jan 2024 18:36:51 +0200 Subject: [PATCH] [Serializer] Rewrite `AbstractObjectNormalizer::createChildContext()` to use the provided `cache_key` from original context when creating child contexts --- .../Normalizer/AbstractObjectNormalizer.php | 6 +- .../AbstractObjectNormalizerTest.php | 125 ++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index a51b69503eb71..ee2af79f38eca 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -781,7 +781,11 @@ private function isMaxDepthReached(array $attributesMetadata, string $class, str protected function createChildContext(array $parentContext, string $attribute, ?string $format): array { $context = parent::createChildContext($parentContext, $attribute, $format); - $context['cache_key'] = $this->getCacheKey($format, $context); + if ($context['cache_key'] ?? false) { + $context['cache_key'] .= '-'.$attribute; + } else { + $context['cache_key'] = $this->getCacheKey($format, $context); + } return $context; } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 4e781c5d81175..368a20032706e 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -548,6 +548,131 @@ public function testDenormalizeUntypedStringObject() $this->assertEquals(new DummyWithStringObject(new DummyString()), $actual); $this->assertEquals('', $actual->value->value); } + + public function testProvidingContextCacheKeyGeneratesSameChildContextCacheKey() + { + $foobar = new Dummy(); + $foobar->foo = new EmptyDummy(); + $foobar->bar = 'bar'; + $foobar->baz = 'baz'; + $data = [ + 'foo' => [], + 'bar' => 'bar', + 'baz' => 'baz', + ]; + + $normalizer = new class() extends AbstractObjectNormalizerDummy { + public $childContextCacheKey; + + protected function extractAttributes(object $object, string $format = null, array $context = []): array + { + return array_keys((array) $object); + } + + protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []) + { + return $object->{$attribute}; + } + + protected function createChildContext(array $parentContext, string $attribute, ?string $format): array + { + $childContext = parent::createChildContext($parentContext, $attribute, $format); + $this->childContextCacheKey = $childContext['cache_key']; + + return $childContext; + } + }; + + $serializer = new Serializer([$normalizer]); + + $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded', 'iri' => '/dummy/1']); + $firstChildContextCacheKey = $normalizer->childContextCacheKey; + + $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded', 'iri' => '/dummy/2']); + $secondChildContextCacheKey = $normalizer->childContextCacheKey; + + $this->assertSame($firstChildContextCacheKey, $secondChildContextCacheKey); + } + + public function testChildContextKeepsOriginalContextCacheKey() + { + $foobar = new Dummy(); + $foobar->foo = new EmptyDummy(); + $foobar->bar = 'bar'; + $foobar->baz = 'baz'; + $data = [ + 'foo' => [], + 'bar' => 'bar', + 'baz' => 'baz', + ]; + + $normalizer = new class() extends AbstractObjectNormalizerDummy { + public $childContextCacheKey; + + protected function extractAttributes(object $object, string $format = null, array $context = []): array + { + return array_keys((array) $object); + } + + protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []) + { + return $object->{$attribute}; + } + + protected function createChildContext(array $parentContext, string $attribute, ?string $format): array + { + $childContext = parent::createChildContext($parentContext, $attribute, $format); + $this->childContextCacheKey = $childContext['cache_key']; + + return $childContext; + } + }; + + $serializer = new Serializer([$normalizer]); + $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded', 'iri' => '/dummy/1']); + + $this->assertSame('hardcoded-foo', $normalizer->childContextCacheKey); + } + + public function testChildContextCacheKeyStaysFalseWhenOriginalCacheKeyIsFalse() + { + $foobar = new Dummy(); + $foobar->foo = new EmptyDummy(); + $foobar->bar = 'bar'; + $foobar->baz = 'baz'; + $data = [ + 'foo' => [], + 'bar' => 'bar', + 'baz' => 'baz', + ]; + + $normalizer = new class() extends AbstractObjectNormalizerDummy { + public $childContextCacheKey; + + protected function extractAttributes(object $object, string $format = null, array $context = []): array + { + return array_keys((array) $object); + } + + protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []) + { + return $object->{$attribute}; + } + + protected function createChildContext(array $parentContext, string $attribute, ?string $format): array + { + $childContext = parent::createChildContext($parentContext, $attribute, $format); + $this->childContextCacheKey = $childContext['cache_key']; + + return $childContext; + } + }; + + $serializer = new Serializer([$normalizer]); + $serializer->normalize($foobar, null, ['cache_key' => false]); + + $this->assertFalse($normalizer->childContextCacheKey); + } } class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer