|
3 | 3 | namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity\Fields\Image; |
4 | 4 |
|
5 | 5 | use Drupal\Core\Cache\RefinableCacheableDependencyInterface; |
| 6 | +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; |
| 7 | +use Drupal\Core\Render\RenderContext; |
| 8 | +use Drupal\Core\Render\RendererInterface; |
6 | 9 | use Drupal\file\FileInterface; |
7 | 10 | use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase; |
8 | 11 | use Drupal\image\Entity\ImageStyle; |
| 12 | +use Symfony\Component\DependencyInjection\ContainerInterface; |
9 | 13 |
|
10 | 14 | /** |
11 | 15 | * @DataProducer( |
|
26 | 30 | * } |
27 | 31 | * ) |
28 | 32 | */ |
29 | | -class ImageDerivative extends DataProducerPluginBase { |
| 33 | +class ImageDerivative extends DataProducerPluginBase implements ContainerFactoryPluginInterface { |
| 34 | + |
| 35 | + /** |
| 36 | + * The rendering service. |
| 37 | + * |
| 38 | + * @var \Drupal\Core\Render\RendererInterface |
| 39 | + */ |
| 40 | + protected $renderer; |
| 41 | + |
| 42 | + /** |
| 43 | + * {@inheritdoc} |
| 44 | + * |
| 45 | + * @codeCoverageIgnore |
| 46 | + */ |
| 47 | + public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) { |
| 48 | + return new static( |
| 49 | + $configuration, |
| 50 | + $pluginId, |
| 51 | + $pluginDefinition, |
| 52 | + $container->get('renderer') |
| 53 | + ); |
| 54 | + } |
| 55 | + |
| 56 | + /** |
| 57 | + * ImageDerivative constructor. |
| 58 | + * |
| 59 | + * @param array $configuration |
| 60 | + * The plugin configuration array. |
| 61 | + * @param string $pluginId |
| 62 | + * The plugin id. |
| 63 | + * @param mixed $pluginDefinition |
| 64 | + * The plugin definition. |
| 65 | + * @param \Drupal\Core\Render\RendererInterface $renderer |
| 66 | + * The renderer service. |
| 67 | + * |
| 68 | + * @codeCoverageIgnore |
| 69 | + */ |
| 70 | + public function __construct( |
| 71 | + array $configuration, |
| 72 | + $pluginId, |
| 73 | + $pluginDefinition, |
| 74 | + RendererInterface $renderer |
| 75 | + ) { |
| 76 | + parent::__construct($configuration, $pluginId, $pluginDefinition); |
| 77 | + $this->renderer = $renderer; |
| 78 | + } |
30 | 79 |
|
31 | 80 | /** |
32 | 81 | * @param \Drupal\file\FileInterface $entity |
@@ -67,8 +116,21 @@ public function resolve(FileInterface $entity = NULL, $style, RefinableCacheable |
67 | 116 | $image_style->transformDimensions($dimensions, $entity->getFileUri()); |
68 | 117 | $metadata->addCacheableDependency($image_style); |
69 | 118 |
|
| 119 | + // The underlying URL generator that will be invoked will leak cache |
| 120 | + // metadata, resulting in an exception. By wrapping within a new render |
| 121 | + // context, we can capture the leaked metadata and make sure it gets |
| 122 | + // incorporated into the response. |
| 123 | + $context = new RenderContext(); |
| 124 | + $url = $this->renderer->executeInRenderContext($context, function () use ($image_style, $entity) { |
| 125 | + return $image_style->buildUrl($entity->getFileUri()); |
| 126 | + }); |
| 127 | + |
| 128 | + if (!$context->isEmpty()) { |
| 129 | + $metadata->addCacheableDependency($context->pop()); |
| 130 | + } |
| 131 | + |
70 | 132 | return [ |
71 | | - 'url' => $image_style->buildUrl($entity->getFileUri()), |
| 133 | + 'url' => $url, |
72 | 134 | 'width' => $dimensions['width'], |
73 | 135 | 'height' => $dimensions['height'], |
74 | 136 | ]; |
|
0 commit comments