diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 3870138..646e428 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -17,6 +17,7 @@
use Drupal\Core\Config\Config;
use Drupal\Core\Config\StorageException;
use Drupal\Core\Render\AttachmentsInterface;
+use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Theme\ThemeSettings;
@@ -401,17 +402,14 @@ function theme_get_setting($setting_name, $theme = NULL) {
* https://www.drupal.org/node/2575065
*/
function theme_render_and_autoescape($arg) {
- // Bubbles argument's cacheability & attachment metadata if necessary.
+ // If it's a renderable, then it'll be up to the generated render array it
+ // returns to contain the necessary cacheability & attachment metadata. If
+ // it doesn't implement CacheableDependencyInterface or AttachmentsInterface
+ // then there is nothing to do here.
if (!($arg instanceof RenderableInterface) && ($arg instanceof CacheableDependencyInterface || $arg instanceof AttachmentsInterface)) {
$arg_bubbleable = [];
- if ($arg instanceof CacheableDependencyInterface) {
- $arg_bubbleable['#cache']['contexts'] = $arg->getCacheContexts();
- $arg_bubbleable['#cache']['tags'] = $arg->getCacheTags();
- $arg_bubbleable['#cache']['max-age'] = $arg->getCacheMaxAge();
- }
- if ($arg instanceof AttachmentsInterface) {
- $arg_bubbleable['#attached'] = $arg->getAttachments();
- }
+ BubbleableMetadata::createFromObject($arg)
+ ->applyTo($arg_bubbleable);
\Drupal::service('renderer')->render($arg_bubbleable);
}
diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php
index 059d1b5..8754ee1 100644
--- a/core/lib/Drupal/Core/Template/TwigExtension.php
+++ b/core/lib/Drupal/Core/Template/TwigExtension.php
@@ -7,6 +7,7 @@
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Render\AttachmentsInterface;
+use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
@@ -491,14 +492,9 @@ protected function bubbleArgMetadata($arg) {
}
$arg_bubbleable = [];
- if ($arg instanceof CacheableDependencyInterface) {
- $arg_bubbleable['#cache']['contexts'] = $arg->getCacheContexts();
- $arg_bubbleable['#cache']['tags'] = $arg->getCacheTags();
- $arg_bubbleable['#cache']['max-age'] = $arg->getCacheMaxAge();
- }
- if ($arg instanceof AttachmentsInterface) {
- $arg_bubbleable['#attached'] = $arg->getAttachments();
- }
+ BubbleableMetadata::createFromObject($arg)
+ ->applyTo($arg_bubbleable);
+
$this->renderer->render($arg_bubbleable);
}
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php
index cc65ffe..b5e19d3 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php
@@ -12,6 +12,7 @@
use Drupal\Core\Link;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\Markup;
+use Drupal\Core\Url;
use Drupal\KernelTests\KernelTestBase;
/**
@@ -93,8 +94,32 @@ public function testThemeEscapeAndRenderNotPrintable() {
*/
public function testBubblingMetadata() {
$link = new GeneratedLink();
- $link->setGeneratedLink('');
+ $link->setGeneratedLink('');
$link->addCacheTags(['foo']);
+ $link->addAttachments(['library' => ['system/base']]);
+
+ $context = new RenderContext();
+ // Use a closure here since we need to render with a render context.
+ $theme_render_and_autoescape = function () use ($link) {
+ return theme_render_and_autoescape($link);
+ };
+ /** @var \Drupal\Core\Render\RendererInterface $renderer */
+ $renderer = \Drupal::service('renderer');
+ $output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
+ $this->assertEquals('', $output);
+ /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
+ $metadata = $context->pop();
+ $this->assertEquals(['foo'], $metadata->getCacheTags());
+ $this->assertEquals(['library' => ['system/base']], $metadata->getAttachments());
+ }
+
+ /**
+ * Ensure cache metadata is bubbled when using theme_render_and_autoescape().
+ */
+ public function testBubblingMetadataWithRenderable() {
+ $link = new Link('', Url::fromUri('http://example.com'));
+ $link->addCacheTags(['foo']);
+ $link->addAttachments(['library' => ['system/base']]);
$context = new RenderContext();
// Use a closure here since we need to render with a render context.
@@ -105,7 +130,10 @@ public function testBubblingMetadata() {
$renderer = \Drupal::service('renderer');
$output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
$this->assertEquals('', $output);
- $this->assertEquals(['foo'], $context->pop()->getCacheTags());
+ /** @var \Drupal\Core\Render\BubbleableMetadata $metadata */
+ $metadata = $context->pop();
+ $this->assertEquals(['foo'], $metadata->getCacheTags());
+ $this->assertEquals(['library' => ['system/base']], $metadata->getAttachments());
}
}
diff --git a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
index de1ba20..ea93703 100644
--- a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
+++ b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
@@ -244,6 +244,7 @@ public function providerTestRenderVar() {
/**
* @covers ::escapeFilter
+ * @covers ::bubbleArgMetadata
*/
public function testEscapeWithGeneratedLink() {
$renderer = $this->prophesize(RendererInterface::class);
@@ -258,27 +259,44 @@ public function testEscapeWithGeneratedLink() {
$twig_extension = new TwigExtension($renderer->reveal());
$twig->addExtension($twig_extension->setUrlGenerator($this->prophesize(UrlGeneratorInterface::class)->reveal()));
$link = new GeneratedLink();
- $link->setGeneratedLink('');
+ $link->setGeneratedLink('');
$link->addCacheTags(['foo']);
+ $link->addAttachments(['library' => ['system/base']]);
$result = $twig_extension->escapeFilter($twig, $link, 'html', NULL, TRUE);
- $renderer->render(["#cache" => ["contexts" => [], "tags" => ["foo"], "max-age" => -1], "#attached" => []])->shouldHaveBeenCalled();
- $this->assertEquals('', $result);
+ $renderer->render([
+ "#cache" => [
+ "contexts" => [],
+ "tags" => ["foo"],
+ "max-age" => -1
+ ],
+ "#attached" => ['library' => ['system/base']],
+ ])->shouldHaveBeenCalled();
+ $this->assertEquals('', $result);
}
/**
* @covers ::renderVar
+ * @covers ::bubbleArgMetadata
*/
public function testRenderVarWithGeneratedLink() {
$renderer = $this->prophesize(RendererInterface::class);
$twig_extension = new TwigExtension($renderer->reveal());
$link = new GeneratedLink();
- $link->setGeneratedLink('');
+ $link->setGeneratedLink('');
$link->addCacheTags(['foo']);
+ $link->addAttachments(['library' => ['system/base']]);
$result = $twig_extension->renderVar($link);
- $renderer->render(["#cache" => ["contexts" => [], "tags" => ["foo"], "max-age" => -1], "#attached" => []])->shouldHaveBeenCalled();
- $this->assertEquals('', $result);
+ $renderer->render([
+ "#cache" => [
+ "contexts" => [],
+ "tags" => ["foo"],
+ "max-age" => -1
+ ],
+ "#attached" => ['library' => ['system/base']],
+ ])->shouldHaveBeenCalled();
+ $this->assertEquals('', $result);
}
}