-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Rewrite AbstractObjectNormalizer::createChildContext()
to use the provided cache_key
from original context
#53523
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey! I see that this is your first PR. That is great! Welcome! Symfony has a contribution guide which I suggest you to read. In short:
Review the GitHub status checks of your pull request and try to solve the reported issues. If some tests are failing, try to see if they are failing because of this change. When two Symfony core team members approve this change, it will be merged and you will become an official Symfony contributor! I am going to sit back now and wait for the reviews. Cheers! Carsonbot |
… 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it's a bug, you must target the 5.4 branch instead.
@@ -287,8 +285,6 @@ abstract protected function extractAttributes(object $object, string $format = n | |||
|
|||
/** | |||
* Gets the attribute value. | |||
* | |||
* @return mixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These coding style changes must not be committed as they don't belong to your bugfix.
@@ -153,9 +153,7 @@ public function supportsNormalization(mixed $data, string $format = null /* , ar | |||
*/ | |||
public function normalize(mixed $object, string $format = null, array $context = []) | |||
{ | |||
if (!isset($context['cache_key'])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd keep this if to avoid calling a method each time. Indeed, calling a method could be costly and we are in the hot path here.
public function denormalize(mixed $data, string $type, string $format = null, array $context = []) | ||
{ | ||
if (!isset($context['cache_key'])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
$normalizer = new class() extends AbstractObjectNormalizerDummy { | ||
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 = []): mixed | ||
{ | ||
return $object->{$attribute}; | ||
} | ||
|
||
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array | ||
{ | ||
$childContext = parent::createChildContext($parentContext, $attribute, $format); | ||
AbstractObjectNormalizerTest::assertSame('hardcoded-'.$attribute, $childContext['cache_key']); | ||
|
||
return $childContext; | ||
} | ||
}; | ||
|
||
$serializer = new Serializer([$normalizer]); | ||
$normalizedObject = $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded']); | ||
$this->assertSame($data, $normalizedObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make sure that an assertion has been made, I'd use a property and make an assertion directly in the test:
$normalizer = new class() extends AbstractObjectNormalizerDummy { | |
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 = []): mixed | |
{ | |
return $object->{$attribute}; | |
} | |
protected function createChildContext(array $parentContext, string $attribute, ?string $format): array | |
{ | |
$childContext = parent::createChildContext($parentContext, $attribute, $format); | |
AbstractObjectNormalizerTest::assertSame('hardcoded-'.$attribute, $childContext['cache_key']); | |
return $childContext; | |
} | |
}; | |
$serializer = new Serializer([$normalizer]); | |
$normalizedObject = $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded']); | |
$this->assertSame($data, $normalizedObject); | |
$normalizer = new class() extends AbstractObjectNormalizerDummy { | |
public ?string $childContextCacheKey = null; | |
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 = []): mixed | |
{ | |
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]); | |
$normalizedObject = $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded']); | |
$this->assertSame($data, $normalizedObject); | |
$this->assertSame('hardcoded-'.$attribute, $normalizer->childContextCacheKey); |
@@ -746,6 +743,10 @@ protected function createChildContext(array $parentContext, string $attribute, ? | |||
*/ | |||
private function getCacheKey(?string $format, array $context): bool|string | |||
{ | |||
if (isset($context['cache_key'])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it go after $context[self::EXCLUDE_FROM_CACHE_KEY]
foreach loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I revert the removal of the inline ifs then this one goes away so it doesn't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But to answer, I don't it should go after because the method would not be called if there is an existing $context['cache_key']
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rebase your PR on the 5.4 branch please? 🙂
|
||
$serializer = new Serializer([$normalizer]); | ||
$normalizedObject = $serializer->normalize($foobar, null, ['cache_key' => 'hardcoded']); | ||
// $this->assertSame($data, $normalizedObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected comment I guess
@@ -302,9 +302,6 @@ public function supportsDenormalization(mixed $data, string $type, string $forma | |||
return class_exists($type) || (interface_exists($type, false) && null !== $this->classDiscriminatorResolver?->getMappingForClass($type)); | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change should be reverted
This can be closed in favor of #53530, thanks! |
AbstractObjectNormalizer::createChildContext()
to use the provided cache_key from original contextAbstractObjectNormalizer::createChildContext()
to use the provided cache_key
from original context
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.