@@ -94,7 +94,7 @@ public function normalize($object, $format = null, array $context = [])
9494 throw new LogicException (sprintf ('Cannot normalize attribute "%s" because the injected serializer is not a normalizer ' , $ attribute ));
9595 }
9696
97- $ data = $ this ->updateData ($ data , $ attribute , $ this ->serializer ->normalize ($ attributeValue , $ format , $ this ->createChildContext ($ context , $ attribute )));
97+ $ data = $ this ->updateData ($ data , $ attribute , $ this ->serializer ->normalize ($ attributeValue , $ format , $ this ->createChildContext ($ context , $ attribute, $ format )));
9898 }
9999
100100 return $ data ;
@@ -128,15 +128,13 @@ protected function getAttributes($object, $format = null, array $context)
128128 return $ allowedAttributes ;
129129 }
130130
131- if (isset ($ context ['attributes ' ])) {
132- return $ this ->extractAttributes ($ object , $ format , $ context );
133- }
131+ $ attributes = $ this ->extractAttributes ($ object , $ format , $ context );
134132
135- if (isset ( $ this -> attributesCache [ $ class ]) ) {
136- return $ this ->attributesCache [$ class ] ;
133+ if ($ context [ ' cache_key ' ] ) {
134+ $ this ->attributesCache [$ key ] = $ attributes ;
137135 }
138136
139- return $ this -> attributesCache [ $ class ] = $ this -> extractAttributes ( $ object , $ format , $ context ) ;
137+ return $ attributes ;
140138 }
141139
142140 /**
@@ -276,7 +274,7 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
276274 throw new LogicException (sprintf ('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer ' , $ attribute , $ class ));
277275 }
278276
279- $ childContext = $ this ->createChildContext ($ context , $ attribute );
277+ $ childContext = $ this ->createChildContext ($ context , $ attribute, $ format );
280278 if ($ this ->serializer ->supportsDenormalization ($ data , $ class , $ format , $ childContext )) {
281279 return $ this ->serializer ->denormalize ($ data , $ class , $ format , $ childContext );
282280 }
@@ -373,7 +371,32 @@ private function isMaxDepthReached(array $attributesMetadata, $class, $attribute
373371 }
374372
375373 /**
376- * Gets the cache key to use.
374+ * Overwritten to update the cache key for the child.
375+ *
376+ * We must not mix up the attribute cache between parent and children.
377+ *
378+ * {@inheritdoc}
379+ */
380+ protected function createChildContext (array $ parentContext , $ attribute/*, string $format = null */ )
381+ {
382+ if (\func_num_args () >= 3 ) {
383+ $ format = \func_get_arg (2 );
384+ } else {
385+ // will be deprecated in version 4
386+ $ format = null ;
387+ }
388+
389+ $ context = parent ::createChildContext ($ parentContext , $ attribute , $ format );
390+ // format is already included in the cache_key of the parent.
391+ $ context ['cache_key ' ] = $ this ->getCacheKey ($ format , $ context );
392+
393+ return $ context ;
394+ }
395+
396+ /**
397+ * Builds the cache key for the attributes cache.
398+ *
399+ * The key must be different for every option in the context that could change which attributes should be handled.
377400 *
378401 * @param string|null $format
379402 * @param array $context
@@ -382,8 +405,13 @@ private function isMaxDepthReached(array $attributesMetadata, $class, $attribute
382405 */
383406 private function getCacheKey ($ format , array $ context )
384407 {
408+ unset($ context ['cache_key ' ]); // avoid artificially different keys
385409 try {
386- return md5 ($ format .serialize ($ context ));
410+ return md5 ($ format .serialize ([
411+ 'context ' => $ context ,
412+ 'ignored ' => $ this ->ignoredAttributes ,
413+ 'camelized ' => $ this ->camelizedAttributes ,
414+ ]));
387415 } catch (\Exception $ exception ) {
388416 // The context cannot be serialized, skip the cache
389417 return false ;
0 commit comments