diff --git a/core/core.services.yml b/core/core.services.yml index c749b8e5639d099cda5f0cfaa76259a25500913a..a0fcf9450e6a9d0ec5c2a530b03242dccff7da42 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1,6 +1,8 @@ parameters: session.storage.options: {} twig.config: {} + renderer.config: + required_cache_contexts: ['languages:language_interface', 'theme'] factory.keyvalue: default: keyvalue.database factory.keyvalue.expirable: @@ -1333,6 +1335,6 @@ services: lazy: true renderer: class: Drupal\Core\Render\Renderer - arguments: ['@controller_resolver', '@theme.manager', '@plugin.manager.element_info', '@request_stack', '@cache_factory', '@cache_contexts'] + arguments: ['@controller_resolver', '@theme.manager', '@plugin.manager.element_info', '@request_stack', '@cache_factory', '@cache_contexts', '%renderer.config%'] email.validator: class: Egulias\EmailValidator\EmailValidator diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 071de3ec5c187e0ccd65b79344f77eab6740a75c..d12d028d6de60d813041eb169f259a7976100e3d 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -170,7 +170,6 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco '#cache' => array( 'tags' => Cache::mergeTags($this->getCacheTags(), $entity->getCacheTags()), 'contexts' => [ - 'theme', 'user.roles', ], ), diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index b1d300e2e6c0d24d67a1bb52cca70a5b9b6de541..9205f6018a63c1012a1b3c23a1e0d7f30c73331b 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -64,6 +64,13 @@ class Renderer implements RendererInterface { */ protected $cacheContexts; + /** + * The renderer configuration array. + * + * @var array + */ + protected $rendererConfig; + /** * The stack containing bubbleable rendering metadata. * @@ -86,14 +93,17 @@ class Renderer implements RendererInterface { * The cache factory. * @param \Drupal\Core\Cache\CacheContexts $cache_contexts * The cache contexts service. + * @param array $renderer_config + * The renderer configuration array. */ - public function __construct(ControllerResolverInterface $controller_resolver, ThemeManagerInterface $theme, ElementInfoManagerInterface $element_info, RequestStack $request_stack, CacheFactoryInterface $cache_factory, CacheContexts $cache_contexts) { + public function __construct(ControllerResolverInterface $controller_resolver, ThemeManagerInterface $theme, ElementInfoManagerInterface $element_info, RequestStack $request_stack, CacheFactoryInterface $cache_factory, CacheContexts $cache_contexts, array $renderer_config) { $this->controllerResolver = $controller_resolver; $this->theme = $theme; $this->elementInfo = $element_info; $this->requestStack = $request_stack; $this->cacheFactory = $cache_factory; $this->cacheContexts = $cache_contexts; + $this->rendererConfig = $renderer_config; } /** @@ -164,10 +174,25 @@ protected function doRender(&$elements, $is_root_call = FALSE) { } static::$stack->push(new BubbleableMetadata()); + // Set the bubbleable rendering metadata that has configurable defaults, if: + // - this is the root call, to ensure that the final render array definitely + // has these configurable defaults, even when no subtree is render cached. + // - this is a render cacheable subtree, to ensure that the cached data has + // the configurable defaults (which may affect the ID and invalidation). + if ($is_root_call || isset($elements['#cache']['keys'])) { + $required_cache_contexts = $this->rendererConfig['required_cache_contexts']; + if (isset($elements['#cache']['contexts'])) { + $elements['#cache']['contexts'] = Cache::mergeContexts($elements['#cache']['contexts'], $required_cache_contexts); + } + else { + $elements['#cache']['contexts'] = $required_cache_contexts; + } + } + // Try to fetch the prerendered element from cache, run any // #post_render_cache callbacks and return the final markup. $pre_bubbling_cid = NULL; - if (isset($elements['#cache'])) { + if (isset($elements['#cache']['keys'])) { $cached_element = $this->cacheGet($elements); if ($cached_element !== FALSE) { $elements = $cached_element; @@ -216,7 +241,6 @@ protected function doRender(&$elements, $is_root_call = FALSE) { } // Defaults for bubbleable rendering metadata. - $elements['#cache']['contexts'] = isset($elements['#cache']['contexts']) ? $elements['#cache']['contexts'] : array(); $elements['#cache']['tags'] = isset($elements['#cache']['tags']) ? $elements['#cache']['tags'] : array(); $elements['#cache']['max-age'] = isset($elements['#cache']['max-age']) ? $elements['#cache']['max-age'] : Cache::PERMANENT; $elements['#attached'] = isset($elements['#attached']) ? $elements['#attached'] : array(); diff --git a/core/modules/block/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php index c2a0ba8960e6f5aa23f099e8f4f6e8dfc1208ac7..9d5c7a88e1d2794a487a71800dc745139e46e54b 100644 --- a/core/modules/block/src/BlockViewBuilder.php +++ b/core/modules/block/src/BlockViewBuilder.php @@ -36,12 +36,6 @@ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = N * {@inheritdoc} */ public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) { - // @todo Remove when https://www.drupal.org/node/2453059 lands. - $default_cache_contexts = [ - 'languages', - 'theme', - ]; - /** @var \Drupal\block\BlockInterface[] $entities */ $build = array(); foreach ($entities as $entity) { @@ -70,7 +64,7 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la '#derivative_plugin_id' => $derivative_id, '#id' => $entity->id(), '#cache' => [ - 'contexts' => Cache::mergeContexts($default_cache_contexts, $plugin->getCacheContexts()), + 'contexts' => $plugin->getCacheContexts(), 'tags' => Cache::mergeTags( $this->getCacheTags(), // Block view builder cache tag. $entity->getCacheTags(), // Block entity cache tag. diff --git a/core/modules/block_content/src/Tests/BlockContentCacheTagsTest.php b/core/modules/block_content/src/Tests/BlockContentCacheTagsTest.php index 5629039bafb827ed55e338d78770e023f0d2c689..8fb80d5da017219e5bb83e93b4b2a8b620bd7644 100644 --- a/core/modules/block_content/src/Tests/BlockContentCacheTagsTest.php +++ b/core/modules/block_content/src/Tests/BlockContentCacheTagsTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Language\LanguageInterface; use Drupal\field\Entity\FieldStorageConfig; use Drupal\system\Tests\Entity\EntityCacheTagsTestBase; use Symfony\Component\HttpFoundation\Request; @@ -80,7 +81,7 @@ public function testBlock() { // Expected keys, contexts, and tags for the block. // @see \Drupal\block\BlockViewBuilder::viewMultiple() $expected_block_cache_keys = ['entity_view', 'block', $block->id()]; - $expected_block_cache_contexts = ['languages', 'theme']; + $expected_block_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme']; $expected_block_cache_tags = Cache::mergeTags(['block_view', 'rendered'], $block->getCacheTags(), $block->getPlugin()->getCacheTags()); // Expected contexts and tags for the BlockContent entity. diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php index a1444c9e5c54c54845e8c307f094e73beac85696..49b99d2d20fee81ce75f8cfac7d3b8172c4a2d2b 100644 --- a/core/modules/filter/src/Tests/FilterAPITest.php +++ b/core/modules/filter/src/Tests/FilterAPITest.php @@ -261,6 +261,9 @@ function testProcessedTextElement() { $expected_cache_contexts = [ // The cache context set by the filter_test_cache_contexts filter. 'languages:' . LanguageInterface::TYPE_CONTENT, + // The default cache contexts for Renderer. + 'languages:' . LanguageInterface::TYPE_INTERFACE, + 'theme', ]; $this->assertEqual($expected_cache_contexts, $build['#cache']['contexts'], 'Expected cache contexts present.'); $expected_markup = '<p>Hello, world!</p><p>This is a dynamic llama.</p>'; diff --git a/core/modules/node/src/Tests/NodeListBuilderTest.php b/core/modules/node/src/Tests/NodeListBuilderTest.php index ec4b1ea89f8de9da77f4b290b6dc4f7534a4829d..798a0566dcf1a764695175cceaf463c3a50e8eb5 100644 --- a/core/modules/node/src/Tests/NodeListBuilderTest.php +++ b/core/modules/node/src/Tests/NodeListBuilderTest.php @@ -7,6 +7,7 @@ namespace Drupal\node\Tests; +use Drupal\Core\Language\LanguageInterface; use Drupal\simpletest\KernelTestBase; /** @@ -36,9 +37,9 @@ public function testCacheContexts() { $list_builder = $this->container->get('entity.manager')->getListBuilder('node'); $build = $list_builder->render(); - $this->container->get('renderer')->render($build); + $this->container->get('renderer')->renderRoot($build); - $this->assertEqual(['url.query_args.pagers:0', 'user.node_grants:view'], $build['#cache']['contexts']); + $this->assertEqual(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0', 'user.node_grants:view'], $build['#cache']['contexts']); } } diff --git a/core/modules/node/src/Tests/Views/FrontPageTest.php b/core/modules/node/src/Tests/Views/FrontPageTest.php index ed6fd3ddcde9cb41409e765b722d6f9a1cc9b895..b8a6910c4c2dbb72a946870bf31c3132bed0e417 100644 --- a/core/modules/node/src/Tests/Views/FrontPageTest.php +++ b/core/modules/node/src/Tests/Views/FrontPageTest.php @@ -8,6 +8,7 @@ namespace Drupal\node\Tests\Views; use Drupal\Core\Cache\Cache; +use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; use Drupal\node\Entity\Node; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; @@ -241,7 +242,13 @@ protected function assertFrontPageViewCacheTags($do_assert_views_caches) { $view = Views::getView('frontpage'); $view->setDisplay('page_1'); - $cache_contexts = ['user.node_grants:view', 'languages']; + $cache_contexts = [ + // Cache contexts associated with the view. + 'user.node_grants:view', + 'languages:' . LanguageInterface::TYPE_INTERFACE, + // Default cache contexts of the renderer. + 'theme', + ]; // Test before there are any nodes. $empty_node_listing_cache_tags = [ @@ -280,7 +287,6 @@ protected function assertFrontPageViewCacheTags($do_assert_views_caches) { $node->save(); } $cache_contexts = Cache::mergeContexts($cache_contexts, [ - 'theme', 'timezone', 'user.roles' ]); diff --git a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php index 8078913da528afb6d2c052513882bf96c861efc5..1fbfcfd61b67e36537ab9215e92ecb0ba343f6c2 100644 --- a/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php +++ b/core/modules/system/src/Tests/Cache/PageCacheTagsIntegrationTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Cache; +use Drupal\Core\Language\LanguageInterface; use Drupal\simpletest\WebTestBase; /** @@ -68,7 +69,7 @@ function testPageCacheTags() { )); $cache_contexts = [ - 'languages', + 'languages:' . LanguageInterface::TYPE_INTERFACE, 'route.menu_active_trails:account', 'route.menu_active_trails:footer', 'route.menu_active_trails:main', diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index 3b382e134d392be6aabe066f50eb4fb5ffe599d2..df0b6d76a3db1ad1fc3c2d023fb462df2bef1de5 100644 --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -10,6 +10,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Entity\FieldConfig; @@ -315,7 +316,8 @@ public function testReferencedEntity() { $nonempty_entity_listing_url = Url::fromRoute('entity.entity_test.collection_labels_alphabetically', ['entity_type_id' => $entity_type]); // The default cache contexts for rendered entities. - $entity_cache_contexts = ['theme', 'user.roles']; + $default_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme']; + $entity_cache_contexts = Cache::mergeContexts($default_cache_contexts, ['user.roles']); // Cache tags present on every rendered page. $page_cache_tags = Cache::mergeTags( @@ -395,7 +397,7 @@ public function testReferencedEntity() { $this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags); // Verify the entity type's list cache contexts are present. $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts'); - $this->assertEqual($this->getAdditionalCacheContextsForEntityListing(), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); + $this->assertEqual(Cache::mergeContexts($default_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); $this->pass("Test listing containing referenced entity.", 'Debug'); @@ -405,7 +407,7 @@ public function testReferencedEntity() { $this->verifyPageCache($nonempty_entity_listing_url, 'HIT', $nonempty_entity_listing_cache_tags); // Verify the entity type's list cache contexts are present. $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts'); - $this->assertEqual($this->getAdditionalCacheContextsForEntityListing(), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); + $this->assertEqual(Cache::mergeContexts($default_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); // Verify that after modifying the referenced entity, there is a cache miss diff --git a/core/modules/system/src/Tests/Entity/EntityListBuilderTest.php b/core/modules/system/src/Tests/Entity/EntityListBuilderTest.php index fa5097a8bac4aa32fed142e75f4163680cd667e0..10becbf5c85524bc7e3d27b6527a0eaea3a7ee6d 100644 --- a/core/modules/system/src/Tests/Entity/EntityListBuilderTest.php +++ b/core/modules/system/src/Tests/Entity/EntityListBuilderTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Entity; +use Drupal\Core\Language\LanguageInterface; use Drupal\simpletest\WebTestBase; /** @@ -64,9 +65,9 @@ public function testCacheContexts() { $list_builder = $this->container->get('entity.manager')->getListBuilder('entity_test'); $build = $list_builder->render(); - $this->container->get('renderer')->render($build); + $this->container->get('renderer')->renderRoot($build); - $this->assertEqual(['entity_test_view_grants', 'url.query_args.pagers:0'], $build['#cache']['contexts']); + $this->assertEqual(['entity_test_view_grants', 'languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0'], $build['#cache']['contexts']); } } diff --git a/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php b/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php index 15881508d5ea12a5f315bf1526c15833c018d858..6e87d2dff28804d71f2aa0edc5b16a0b9c0f0bd7 100644 --- a/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php +++ b/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php @@ -7,7 +7,9 @@ namespace Drupal\system\Tests\Entity; +use Drupal\Core\Language\LanguageInterface; use Drupal\entity_reference\Tests\EntityReferenceTestTrait; +use Drupal\Core\Cache\Cache; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; @@ -61,7 +63,7 @@ public function testEntityViewBuilderCache() { // Get a fully built entity view render array. $entity_test->save(); $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys(Cache::mergeContexts($build['#cache']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme']))); $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; @@ -111,7 +113,7 @@ public function testEntityViewBuilderCacheWithReferences() { // Get a fully built entity view render array for the referenced entity. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test_reference, 'full'); - $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys(Cache::mergeContexts($build['#cache']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme']))); $cid_reference = implode(':', $cid_parts); $bin_reference = $build['#cache']['bin']; @@ -130,7 +132,7 @@ public function testEntityViewBuilderCacheWithReferences() { // Get a fully built entity view render array. $build = $this->container->get('entity.manager')->getViewBuilder('entity_test')->view($entity_test, 'full'); - $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys(Cache::mergeContexts($build['#cache']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme']))); $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; diff --git a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php index c72d7d0bfc82a064c1483553a2555186cff592eb..299f811127756588c3feb55aed277970e7a316eb 100644 --- a/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityWithUriCacheTagsTestBase.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Entity; use Drupal\Core\Cache\Cache; +use Drupal\Core\Language\LanguageInterface; use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Entity\FieldConfig; @@ -31,7 +32,7 @@ public function testEntityUri() { $view_mode = $this->selectViewMode($entity_type); // The default cache contexts for rendered entities. - $entity_cache_contexts = ['theme', 'user.roles']; + $entity_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.roles']; // Generate the standardized entity cache tags. $cache_tag = $this->entity->getCacheTags(); diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index 24d1ec387100075da1539f5cea6bc87e1fd23e13..3a21a1379b4d5cdae2207f8af54134661fb31e65 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -11,6 +11,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Language\LanguageInterface; use Drupal\views\Views; use Drupal\views\ViewEntityInterface; @@ -316,9 +317,9 @@ protected function addCacheMetadata() { $executable->setDisplay($display_id); list($display['cache_metadata']['cacheable'], $display['cache_metadata']['contexts']) = $executable->getDisplay()->calculateCacheMetadata(); - // Always include at least the 'languages' context as there will most + // Always include at least the 'languages:' context as there will most // probably be translatable strings in the view output. - $display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages']); + $display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE]); } // Restore the previous active display. $executable->setDisplay($current_display); diff --git a/core/modules/views/src/Tests/GlossaryTest.php b/core/modules/views/src/Tests/GlossaryTest.php index 954f7edfc3462a20209f45c5ba9387195943fd29..91ccead78e9c9adcc4bbfdbfe470b254a56c9727 100644 --- a/core/modules/views/src/Tests/GlossaryTest.php +++ b/core/modules/views/src/Tests/GlossaryTest.php @@ -8,6 +8,7 @@ namespace Drupal\views\Tests; use Drupal\Component\Utility\Unicode; +use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; use Drupal\views\Views; @@ -87,7 +88,7 @@ public function testGlossaryView() { // Verify cache tags. $this->enablePageCaching(); - $this->assertPageCacheContextsAndTags(Url::fromRoute('view.glossary.page_1'), ['languages', 'url', 'user.node_grants:view'], [ + $this->assertPageCacheContextsAndTags(Url::fromRoute('view.glossary.page_1'), ['languages', 'theme', 'url', 'user.node_grants:view'], [ 'config:views.view.glossary', 'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(), 'node_list', diff --git a/core/modules/views/src/Tests/RenderCacheIntegrationTest.php b/core/modules/views/src/Tests/RenderCacheIntegrationTest.php index ad2621a78d5469c79d3eb2ef1906fe93e3a1209d..4eda894d05c683c0dc798c734c7c412f7f40e6ff 100644 --- a/core/modules/views/src/Tests/RenderCacheIntegrationTest.php +++ b/core/modules/views/src/Tests/RenderCacheIntegrationTest.php @@ -8,6 +8,7 @@ namespace Drupal\views\Tests; use Drupal\Core\Cache\Cache; +use Drupal\Core\Language\LanguageInterface; use Drupal\entity_test\Entity\EntityTest; use Drupal\views\Views; use Drupal\views\Entity\View; @@ -221,7 +222,7 @@ public function testViewAddCacheMetadata() { $view = View::load('test_display'); $view->save(); - $this->assertEqual(['languages', 'user.node_grants:view'], $view->getDisplay('default')['cache_metadata']['contexts']); + $this->assertEqual(['languages', 'languages:' . LanguageInterface::TYPE_INTERFACE, 'user.node_grants:view'], $view->getDisplay('default')['cache_metadata']['contexts']); } } diff --git a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php index efe5ef585c85aa9ec461965086fcdce09450db53..7e5abf420c2b20271ac4d01471651a4e4a1d0641 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php @@ -9,6 +9,7 @@ use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; use Drupal\Core\Render\Element; +use Drupal\Core\Render\Renderer; use Drupal\Core\State\State; use Drupal\Core\Cache\Cache; @@ -22,6 +23,10 @@ class RendererBubblingTest extends RendererTestBase { * {@inheritdoc} */ protected function setUp() { + // Disable the required cache contexts, so that this test can test just the + // bubbling behavior. + $this->rendererConfig['required_cache_contexts'] = []; + parent::setUp(); $this->setUpRequest(); @@ -249,21 +254,6 @@ public function testConditionalCacheContextBubblingSelfHealing() { $this->setUpRequest(); $this->setupMemoryCache(); - $this->cacheContexts->expects($this->any()) - ->method('convertTokensToKeys') - ->willReturnCallback(function($context_tokens) { - global $current_user_role; - $keys = []; - foreach ($context_tokens as $context_id) { - if ($context_id === 'user.roles') { - $keys[] = 'r.' . $current_user_role; - } - else { - $keys[] = $context_id; - } - } - return $keys; - }); $test_element = [ '#cache' => [ diff --git a/core/tests/Drupal/Tests/Core/Render/RendererPostRenderCacheTest.php b/core/tests/Drupal/Tests/Core/Render/RendererPostRenderCacheTest.php index c76554da8bcb68036a47962f2f6c3ec82358c609..9cddf0740754a1923afab81958f7a6e8a13ab601 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererPostRenderCacheTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererPostRenderCacheTest.php @@ -17,6 +17,17 @@ */ class RendererPostRenderCacheTest extends RendererTestBase { + /** + * {@inheritdoc} + */ + protected function setUp() { + // Disable the required cache contexts, so that this test can test just the + // #post_render_cache behavior. + $this->rendererConfig['required_cache_contexts'] = []; + + parent::setUp(); + } + /** * Generates an element with a #post_render_cache callback. * diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php index 36cc3bc9a0b3e582270797dadf2677ab2d840e54..7ac67b1b4b90d5a36f3750dde8f74a161b85edbb 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php @@ -19,7 +19,10 @@ class RendererTest extends RendererTestBase { protected $defaultThemeVars = [ '#cache' => [ - 'contexts' => [], + 'contexts' => [ + 'languages:language_interface', + 'theme', + ], 'tags' => [], 'max-age' => Cache::PERMANENT, ], @@ -499,7 +502,7 @@ public function testRenderWithoutThemeArguments() { ->willReturn('foobar'); // Test that defaults work. - $this->assertEquals($this->renderer->render($element), 'foobar', 'Defaults work'); + $this->assertEquals($this->renderer->renderRoot($element), 'foobar', 'Defaults work'); } /** @@ -521,7 +524,7 @@ public function testRenderWithThemeArguments() { }); // Tests that passing arguments to the theme function works. - $this->assertEquals($this->renderer->render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works'); + $this->assertEquals($this->renderer->renderRoot($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works'); } /** @@ -573,7 +576,7 @@ public function testRenderCache() { $this->assertEquals($expected_tags, $element['#cache']['tags'], 'Cache tags were collected from the element and its subchild.'); // The cache item also has a 'rendered' cache tag. - $cache_item = $this->cacheFactory->get('render')->get('render_cache_test'); + $cache_item = $this->cacheFactory->get('render')->get('render_cache_test:en:stark'); $this->assertSame(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags); } @@ -599,7 +602,7 @@ public function testRenderCacheMaxAge($max_age, $is_render_cached, $render_cache ]; $this->renderer->render($element); - $cache_item = $this->cacheFactory->get('render')->get('render_cache_test'); + $cache_item = $this->cacheFactory->get('render')->get('render_cache_test:en:stark'); if (!$is_render_cached) { $this->assertFalse($cache_item); } diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php index 15a3b052f85a1bec8e4ebdd9997fa33f7415debc..28aec89c7d5b5a942a165d53b4057ac965ff6ff6 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\MemoryBackend; +use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Render\Element; use Drupal\Core\Render\Renderer; use Drupal\Tests\UnitTestCase; @@ -69,6 +70,18 @@ class RendererTestBase extends UnitTestCase { */ protected $memoryCache; + /** + * The mocked renderer configuration. + * + * @var array + */ + protected $rendererConfig = [ + 'required_cache_contexts' => [ + 'languages:language_interface', + 'theme', + ], + ]; + /** * {@inheritdoc} */ @@ -83,7 +96,29 @@ protected function setUp() { $this->cacheContexts = $this->getMockBuilder('Drupal\Core\Cache\CacheContexts') ->disableOriginalConstructor() ->getMock(); - $this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->requestStack, $this->cacheFactory, $this->cacheContexts); + $this->cacheContexts->expects($this->any()) + ->method('convertTokensToKeys') + ->willReturnCallback(function($context_tokens) { + global $current_user_role; + $keys = []; + foreach ($context_tokens as $context_id) { + switch ($context_id) { + case 'user.roles': + $keys[] = 'r.' . $current_user_role; + break; + case 'languages:language_interface': + $keys[] = 'en'; + break; + case 'theme': + $keys[] = 'stark'; + break; + default: + $keys[] = $context_id; + } + } + return $keys; + }); + $this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->requestStack, $this->cacheFactory, $this->cacheContexts, $this->rendererConfig); $container = new ContainerBuilder(); $container->set('cache_contexts', $this->cacheContexts); diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml index 77e99ccf6a90a2781f52361283506cf7ee6cf94e..c44c73b9c9fa50d9f355ef98ce877b7b3503e51c 100644 --- a/sites/default/default.services.yml +++ b/sites/default/default.services.yml @@ -76,6 +76,14 @@ parameters: # Not recommended in production environments # @default true cache: true + renderer.config: + # Renderer required cache contexts: + # + # The Renderer will automatically associate these cache contexts with every + # render array, hence varying every render array by these cache contexts. + # + # @default ['languages:language_interface', 'theme'] + required_cache_contexts: ['languages:language_interface', 'theme'] factory.keyvalue: {} # Default key/value storage service to use.