diff --git a/src/Serializer/Serializer.php b/src/Serializer/Serializer.php index 97c5629..85869a8 100644 --- a/src/Serializer/Serializer.php +++ b/src/Serializer/Serializer.php @@ -2,11 +2,9 @@ namespace Drupal\jsonapi\Serializer; -use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Cache\CacheableMetadata; use Drupal\jsonapi\Normalizer\CacheableNormalizerInterface as JsonApiCacheableNormalizerInterface; use Drupal\jsonapi\Normalizer\Value\CacheableNormalization; -use Drupal\jsonapi\Normalizer\Value\CacheableOmission; use Drupal\serialization\Normalizer\CacheableNormalizerInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -67,26 +65,18 @@ final class Serializer extends SymfonySerializer implements JsonApiCacheableNorm // out-of-band. if ($normalizer = $this->getNormalizer($data, $format, $context)) { $normalization = $normalizer->getCacheableNormalization($data, $format, $context); - static::applyContextCacheability($context, $normalization); + $context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY] = isset($context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY]) + ? $context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY]->addCacheableDependency($normalization) + : CacheableMetadata::createFromObject($normalization); return $normalization->getNormalization(); } - // In case the data is traversable, normalize its children and unwrap any - // CacheableNormalizations so that the return type expectations for - // NormalizerInterface::normalize() are preserved. The cacheability will be - // preserved by adding it to the out-of-band context cacheability mechanism. + if ($this->fallbackNormalizer->supportsNormalization($data, $format, $context)) { + return $this->fallbackNormalizer->normalize($data, $format, $context); + } + // Before completely falling back to the fallback normalizer, if the data is + // an array or traversable, attempt to normalize it. if (\is_array($data) || $data instanceof \Traversable) { - $normalized = parent::normalize($data, $format, $context); - foreach ($normalized as $key => $item) { - if ($item instanceof CacheableOmission) { - static::applyContextCacheability($context, $item); - unset($normalized[$key]); - } - elseif ($item instanceof CacheableNormalization) { - static::applyContextCacheability($context, $item); - $normalized[$key] = $item->getNormalization(); - } - } - return $normalized; + return parent::normalize($data, $format, $context); } // None of this serializer's normalizers are able to normalize the data, // so use the fallback normalizer. @@ -196,18 +186,4 @@ final class Serializer extends SymfonySerializer implements JsonApiCacheableNorm return parent::supportsDenormalization($data, $type, $format, $context); } - /** - * Adds a cacheable dependency to a normalization context. - * - * @param array $context - * The normalization context. - * @param \Drupal\Core\Cache\CacheableDependencyInterface $dependency - * The cacheable dependency. - */ - protected static function applyContextCacheability(array &$context, CacheableDependencyInterface $dependency) { - $context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY] = isset($context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY]) - ? $context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY]->merge($dependency) - : CacheableMetadata::createFromObject($dependency); - } - } diff --git a/tests/modules/jsonapi_test_data_type/src/TraversableObject.php b/tests/modules/jsonapi_test_data_type/src/TraversableObject.php index daf672c..79b44fc 100644 --- a/tests/modules/jsonapi_test_data_type/src/TraversableObject.php +++ b/tests/modules/jsonapi_test_data_type/src/TraversableObject.php @@ -13,7 +13,7 @@ class TraversableObject implements \IteratorAggregate { * {@inheritdoc} */ public function getIterator() { - return new \ArrayIterator($this); + return new \ArrayIterator(); } } diff --git a/tests/src/Kernel/Serializer/SerializerTest.php b/tests/src/Kernel/Serializer/SerializerTest.php index 75b5b92..2e21365 100644 --- a/tests/src/Kernel/Serializer/SerializerTest.php +++ b/tests/src/Kernel/Serializer/SerializerTest.php @@ -95,11 +95,29 @@ class SerializerTest extends JsonapiKernelTestBase { 'processed' => '', ]; $data = $this->node->field_text; + $array_of_data = [$data]; + $traversable_data = new \ArrayIterator($array_of_data); + $normalization = $this->sut->normalize($data, 'api_json', $context); $cacheable_normalization = $this->sut->getCacheableNormalization($data, 'api_json', $context); + $this->assertSame($expected_normalization, $normalization); $this->assertTrue($cacheable_normalization instanceof CacheableNormalization); $this->assertSame($expected_normalization, $cacheable_normalization->getNormalization()); + + $array_normalization = $this->sut->normalize($array_of_data, 'api_json', $context); + $cacheable_array_normalization = $this->sut->getCacheableNormalization($array_of_data, 'api_json', $context); + + $this->assertSame([$expected_normalization], $array_normalization); + $this->assertTrue($cacheable_array_normalization instanceof CacheableNormalization); + $this->assertSame([$expected_normalization], $cacheable_array_normalization->getNormalization()); + + $traversable_normalization = $this->sut->normalize($traversable_data, 'api_json', $context); + $cacheable_traversable_normalization = $this->sut->getCacheableNormalization($traversable_data, 'api_json', $context); + + $this->assertSame([$expected_normalization], $traversable_normalization); + $this->assertTrue($cacheable_traversable_normalization instanceof CacheableNormalization); + $this->assertSame([$expected_normalization], $cacheable_traversable_normalization->getNormalization()); } /** @@ -123,7 +141,7 @@ class SerializerTest extends JsonapiKernelTestBase { */ public function providerFallbackNormalizer() { return [ - [($traversableObject = new TraversableObject()), ['property' => $traversableObject->property]], + [($traversableObject = new TraversableObject()), $traversableObject->property], [Markup::create('