Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 96af30f

Browse files
committed
[Serializer] Rewrite AbstractObjectNormalizer::createChildContext() to use the provided cache_key from original context when creating child contexts
If the normalization starts with an initial 'cache_key' it is currently discarded when creating child contexts. This change fixes that. The main reason behind it is that if the client code sends a unique identifier (ApiPlatform injects the IRI) and we have a use case that iterates a big resultset we end up with a big private cache that quickly runs out of allowed memory. The solution should be to send a 'cache_key' which ignores the entire cache key calculation that hashes the context.
1 parent 914c288 commit 96af30f

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,7 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar
153153
*/
154154
public function normalize(mixed $object, string $format = null, array $context = [])
155155
{
156-
if (!isset($context['cache_key'])) {
157-
$context['cache_key'] = $this->getCacheKey($format, $context);
158-
}
156+
$context['cache_key'] = $this->getCacheKey($format, $context);
159157

160158
$this->validateCallbackContext($context);
161159

@@ -287,8 +285,6 @@ abstract protected function extractAttributes(object $object, string $format = n
287285

288286
/**
289287
* Gets the attribute value.
290-
*
291-
* @return mixed
292288
*/
293289
abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []);
294290

@@ -302,14 +298,9 @@ public function supportsDenormalization(mixed $data, string $type, string $forma
302298
return class_exists($type) || (interface_exists($type, false) && null !== $this->classDiscriminatorResolver?->getMappingForClass($type));
303299
}
304300

305-
/**
306-
* @return mixed
307-
*/
308301
public function denormalize(mixed $data, string $type, string $format = null, array $context = [])
309302
{
310-
if (!isset($context['cache_key'])) {
311-
$context['cache_key'] = $this->getCacheKey($format, $context);
312-
}
303+
$context['cache_key'] = $this->getCacheKey($format, $context);
313304

314305
$this->validateCallbackContext($context);
315306

@@ -734,7 +725,13 @@ private function isMaxDepthReached(array $attributesMetadata, string $class, str
734725
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array
735726
{
736727
$context = parent::createChildContext($parentContext, $attribute, $format);
737-
$context['cache_key'] = $this->getCacheKey($format, $context);
728+
if (isset($context['cache_key'])) {
729+
if (false !== $context['cache_key']) {
730+
$context['cache_key'] .= '-'.$attribute;
731+
}
732+
} else {
733+
$context['cache_key'] = $this->getCacheKey($format, $context);
734+
}
738735

739736
return $context;
740737
}
@@ -746,6 +743,10 @@ protected function createChildContext(array $parentContext, string $attribute, ?
746743
*/
747744
private function getCacheKey(?string $format, array $context): bool|string
748745
{
746+
if (isset($context['cache_key'])) {
747+
return $context['cache_key'];
748+
}
749+
749750
foreach ($context[self::EXCLUDE_FROM_CACHE_KEY] ?? $this->defaultContext[self::EXCLUDE_FROM_CACHE_KEY] as $key) {
750751
unset($context[$key]);
751752
}

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,43 @@ public function supportsNormalization(mixed $data, string $format = null, array
788788
$this->assertSame('called', $object->bar);
789789
}
790790

791+
public function testChildContextKeepsOriginalContextCacheKey()
792+
{
793+
$foobar = new Dummy();
794+
$foobar->foo = new EmptyDummy();
795+
$foobar->bar = 'bar';
796+
$foobar->baz = 'baz';
797+
$data = [
798+
'foo' => [],
799+
'bar' => 'bar',
800+
'baz' => 'baz',
801+
];
802+
803+
$normalizer = new class() extends AbstractObjectNormalizerDummy {
804+
protected function extractAttributes(object $object, string $format = null, array $context = []): array
805+
{
806+
return array_keys((array) $object);
807+
}
808+
809+
protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []): mixed
810+
{
811+
return $object->{$attribute};
812+
}
813+
814+
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array
815+
{
816+
$childContext = parent::createChildContext($parentContext, $attribute, $format);
817+
AbstractObjectNormalizerTest::assertSame('hardcoded-'.$attribute, $childContext['cache_key']);
818+
819+
return $childContext;
820+
}
821+
};
822+
823+
$serializer = new Serializer([$normalizer]);
824+
$normalizedObject = $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded']);
825+
$this->assertSame($data, $normalizedObject);
826+
}
827+
791828
public function testDenormalizeUnionOfEnums()
792829
{
793830
$serializer = new Serializer([

0 commit comments

Comments
 (0)