diff --git a/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php new file mode 100644 index 0000000..4403da4 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php @@ -0,0 +1,42 @@ +renderer()->hasRenderContext()) { + $build = []; + CacheableMetadata::createFromObject($object)->applyTo($build); + $this->renderer()->render($build); + } + } + + /** + * Gets the render service. + * + * @return \Drupal\Core\Render\RendererInterface + * The renderer. + */ + protected function renderer() { + return isset($this->renderer) ? $this->renderer : \Drupal::service('renderer'); + } + +} diff --git a/core/modules/image/src/ImageServiceProvider.php b/core/modules/image/src/ImageServiceProvider.php new file mode 100644 index 0000000..24b4a4a --- /dev/null +++ b/core/modules/image/src/ImageServiceProvider.php @@ -0,0 +1,34 @@ +getParameter('container.modules'); + if (isset($modules['serialization'])) { + // Add an ImageItem normalizer. + $service_definition = new Definition(ImageItemNormalizer::class, [ + new Reference('entity_type.manager'), + ]); + // Priority should be higher than + // serializer.normalizer.entity_reference_field_item but lower than + // serializer.normalizer.entity_reference_item.hal. + $service_definition->addTag('normalizer', ['priority' => 7]); + $container->setDefinition('image.normalizer.image_item', $service_definition); + } + } + +} diff --git a/core/modules/image/src/Normalizer/ImageItemNormalizer.php b/core/modules/image/src/Normalizer/ImageItemNormalizer.php new file mode 100644 index 0000000..413d637 --- /dev/null +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php @@ -0,0 +1,62 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public function normalize($object, $format = NULL, array $context = array()) { + $data = parent::normalize($object, $format, $context); + if (empty($data['target_id'])) { + return $data; + } + /** @var \Drupal\file\FileInterface $image */ + $image = File::load($data['target_id']); + $uri = $image->getFileUri(); + /** @var \Drupal\image\ImageStyleInterface[] $styles */ + $styles = ImageStyle::loadMultiple(); + $data['image_styles'] = []; + foreach ($styles as $id => $style) { + $data['image_styles'][$id] = file_url_transform_relative($style->buildUrl($uri)); + $this->bubble($style); + } + return $data; + } + +} diff --git a/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php new file mode 100644 index 0000000..3cb2cce --- /dev/null +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php @@ -0,0 +1,108 @@ +serializer = \Drupal::service('serializer'); + + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('user'); + $this->installEntitySchema('file'); + $this->installConfig('system'); + $this->installConfig('image'); + $this->installSchema('file', ['file_usage']); + + FieldStorageConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'type' => 'image', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'bundle' => 'entity_test', + 'settings' => [ + 'file_extensions' => 'jpg', + ], + ])->save(); + + file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg'); + $this->image = File::create([ + 'uri' => 'public://example.jpg', + ]); + $this->image->save(); + $this->imageFactory = $this->container->get('image.factory'); + } + + /** + * @covers ::normalize + */ + public function testNormalize() { + // Create a test entity with the image field set. + $original_entity = EntityTest::create(); + $original_entity->image_test->target_id = $this->image->id(); + $original_entity->image_test->alt = $alt = $this->randomMachineName(); + $original_entity->image_test->title = $title = $this->randomMachineName(); + $original_entity->name->value = $this->randomMachineName(); + $original_entity->save(); + + $entity = clone $original_entity; + $context = new RenderContext(); + $data = $this->container->get('renderer') + ->executeInRenderContext($context, function () use ($entity) { + return $this->serializer->normalize($entity); + }); + $cacheability = new BubbleableMetadata(); + $cache_tags = []; + /** @var \Drupal\image\ImageStyleInterface $image_style */ + foreach (ImageStyle::loadMultiple() as $image_style) { + $cache_tags = Cache::mergeTags($cache_tags, $image_style->getCacheTags()); + } + $cacheability->setCacheTags($cache_tags); + + $image_style_ids = array_keys($data['image_test'][0]['image_styles']); + $expected_image_style_keys = ['large', 'medium', 'thumbnail']; + $this->assertEquals($cacheability, $context->pop()); + $this->assertEquals($expected_image_style_keys, $image_style_ids); + + foreach ($data['image_test'][0]['image_styles'] as $id => $url) { + $this->assertNotEmpty(strstr($url, "files/styles/$id/public/example.jpg")); + } + } + +}