[Serializer] Respect ignored attributes in cache key of normalizer

This commit is contained in:
David Buchmann 2019-04-06 16:28:08 +02:00 committed by Fabien Potencier
parent b30f57e14b
commit 926d228877
3 changed files with 54 additions and 15 deletions

View File

@ -397,7 +397,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
}
$parameterClass = $parameter->getClass()->getName();
return $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName));
return $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $parameterName, $format));
}
return $parameterData;
@ -407,14 +407,15 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
}
/**
* @param array $parentContext
* @param string $attribute
* @param array $parentContext
* @param string $attribute Attribute name
* @param string|null $format
*
* @return array
*
* @internal
*/
protected function createChildContext(array $parentContext, $attribute)
protected function createChildContext(array $parentContext, $attribute/*, string $format = null */)
{
if (isset($parentContext[self::ATTRIBUTES][$attribute])) {
$parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute];

View File

@ -94,7 +94,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
throw new LogicException(sprintf('Cannot normalize attribute "%s" because the injected serializer is not a normalizer', $attribute));
}
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)));
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute, $format)));
}
return $data;
@ -128,15 +128,13 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
return $allowedAttributes;
}
if (isset($context['attributes'])) {
return $this->extractAttributes($object, $format, $context);
$attributes = $this->extractAttributes($object, $format, $context);
if ($context['cache_key']) {
$this->attributesCache[$key] = $attributes;
}
if (isset($this->attributesCache[$class])) {
return $this->attributesCache[$class];
}
return $this->attributesCache[$class] = $this->extractAttributes($object, $format, $context);
return $attributes;
}
/**
@ -276,7 +274,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
throw new LogicException(sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer', $attribute, $class));
}
$childContext = $this->createChildContext($context, $attribute);
$childContext = $this->createChildContext($context, $attribute, $format);
if ($this->serializer->supportsDenormalization($data, $class, $format, $childContext)) {
return $this->serializer->denormalize($data, $class, $format, $childContext);
}
@ -373,7 +371,32 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
}
/**
* Gets the cache key to use.
* Overwritten to update the cache key for the child.
*
* We must not mix up the attribute cache between parent and children.
*
* {@inheritdoc}
*/
protected function createChildContext(array $parentContext, $attribute/*, string $format = null */)
{
if (\func_num_args() >= 3) {
$format = \func_get_arg(2);
} else {
// will be deprecated in version 4
$format = null;
}
$context = parent::createChildContext($parentContext, $attribute, $format);
// format is already included in the cache_key of the parent.
$context['cache_key'] = $this->getCacheKey($format, $context);
return $context;
}
/**
* Builds the cache key for the attributes cache.
*
* The key must be different for every option in the context that could change which attributes should be handled.
*
* @param string|null $format
* @param array $context
@ -382,8 +405,13 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
*/
private function getCacheKey($format, array $context)
{
unset($context['cache_key']); // avoid artificially different keys
try {
return md5($format.serialize($context));
return md5($format.serialize([
'context' => $context,
'ignored' => $this->ignoredAttributes,
'camelized' => $this->camelizedAttributes,
]));
} catch (\Exception $exception) {
// The context cannot be serialized, skip the cache
return false;

View File

@ -380,6 +380,16 @@ class ObjectNormalizerTest extends TestCase
['fooBar' => 'foobar'],
$this->normalizer->normalize($obj, 'any')
);
$this->normalizer->setIgnoredAttributes(['foo', 'baz', 'camelCase', 'object']);
$this->assertEquals(
[
'fooBar' => 'foobar',
'bar' => 'bar',
],
$this->normalizer->normalize($obj, 'any')
);
}
public function testIgnoredAttributesDenormalize()