diff -u b/core/lib/Drupal/Core/Cache/Context/AccountPermissionsCacheContext.php b/core/lib/Drupal/Core/Cache/Context/AccountPermissionsCacheContext.php --- b/core/lib/Drupal/Core/Cache/Context/AccountPermissionsCacheContext.php +++ b/core/lib/Drupal/Core/Cache/Context/AccountPermissionsCacheContext.php @@ -55,6 +55,7 @@ * {@inheritdoc} */ public function getCacheTags() { + $tags = []; foreach ($this->user->getRoles() as $role) { $tags[] = "config:user.role.$role"; } diff -u b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php --- b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php +++ b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php @@ -113,7 +113,7 @@ list($context_id, $parameter) = $context_token; $context = $this->getService($context_id); if ($context instanceof CacheableCacheContextInterface || $context instanceof CacheableCalculatedCacheContextInterface) { - $cacheable_metadata->addCacheTags($context->getCacheableMetadata()->getCacheTags()); + $cacheable_metadata = $cacheable_metadata->merge(CacheableMetadata::createFromObject($context->getCacheableMetadata())); } } diff -u b/core/lib/Drupal/Core/Render/RenderCache.php b/core/lib/Drupal/Core/Render/RenderCache.php --- b/core/lib/Drupal/Core/Render/RenderCache.php +++ b/core/lib/Drupal/Core/Render/RenderCache.php @@ -306,10 +306,9 @@ if (!empty($elements['#cache']['contexts'])) { $contexts = $this->cacheContextsManager->convertTokensToKeys($elements['#cache']['contexts']); $cid_parts = array_merge($cid_parts, $contexts['contexts']); - if (!isset($elements['#cache']['tags'])) { - $elements['#cache']['tags'] = []; - } - $elements['#cache']['tags'] = Cache::mergeTags($elements['#cache']['tags'], $contexts['cacheable_metadata']->getCacheTags()); + CacheableMetadata::createFromRenderArray($elements) + ->merge($contexts['cacheable_metadata']) + ->applyTo($elements); } return implode(':', $cid_parts); } only in patch2: unchanged: --- a/core/modules/comment/src/Tests/CommentCacheTagsTest.php +++ b/core/modules/comment/src/Tests/CommentCacheTagsTest.php @@ -102,6 +102,7 @@ protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) { /** @var \Drupal\comment\CommentInterface $entity */ return array( 'config:filter.format.plain_text', + 'config:user.role.anonymous', 'user:' . $entity->getOwnerId(), 'user_view', ); only in patch2: unchanged: --- a/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php +++ b/core/modules/comment/src/Tests/CommentDefaultFormatterCacheTagsTest.php @@ -7,6 +7,7 @@ namespace Drupal\comment\Tests; +use Drupal\Core\Cache\Cache; use Drupal\Core\Session\UserSession; use Drupal\comment\CommentInterface; use Drupal\system\Tests\Entity\EntityUnitTestBase; @@ -69,7 +70,8 @@ public function testCacheTags() { ->getViewBuilder('entity_test') ->view($commented_entity); $renderer->renderRoot($build); - $expected_cache_tags = array( + $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($build['#cache']['contexts'])['cacheable_metadata']->getCacheTags(); + $expected_cache_tags = Cache::mergeTags($cache_context_tags, [ 'entity_test_view', 'entity_test:' . $commented_entity->id(), 'comment_list', @@ -78,9 +80,9 @@ public function testCacheTags() { 'config:field.field.entity_test.entity_test.comment', 'config:field.storage.comment.comment_body', 'config:user.settings', - ); + ]); sort($expected_cache_tags); - $this->assertEqual($build['#cache']['tags'], $expected_cache_tags, 'The test entity has the expected cache tags before it has comments.'); + $this->assertEqual($build['#cache']['tags'], $expected_cache_tags); // Create a comment on that entity. Comment loading requires that the uid // also exists in the {users} table. @@ -111,7 +113,8 @@ public function testCacheTags() { ->getViewBuilder('entity_test') ->view($commented_entity); $renderer->renderRoot($build); - $expected_cache_tags = array( + $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($build['#cache']['contexts'])['cacheable_metadata']->getCacheTags(); + $expected_cache_tags = Cache::mergeTags($cache_context_tags, [ 'entity_test_view', 'entity_test:' . $commented_entity->id(), 'comment_list', @@ -125,9 +128,9 @@ public function testCacheTags() { 'config:field.field.entity_test.entity_test.comment', 'config:field.storage.comment.comment_body', 'config:user.settings', - ); + ]); sort($expected_cache_tags); - $this->assertEqual($build['#cache']['tags'], $expected_cache_tags, 'The test entity has the expected cache tags when it has comments.'); + $this->assertEqual($build['#cache']['tags'], $expected_cache_tags); } } only in patch2: unchanged: --- a/core/modules/comment/src/Tests/CommentRssTest.php +++ b/core/modules/comment/src/Tests/CommentRssTest.php @@ -8,6 +8,7 @@ namespace Drupal\comment\Tests; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; +use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; @@ -52,16 +53,22 @@ function testCommentRss() { $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName()); $this->drupalGet('rss.xml'); - $this->assertCacheTags([ - 'config:views.view.frontpage', 'node:1', 'node_list', 'node_view', 'user:3', - ]); - $this->assertCacheContexts([ + $cache_contexts = [ 'languages:language_interface', 'theme', 'user.node_grants:view', 'user.permissions', 'timezone', - ]); + ]; + $this->assertCacheContexts($cache_contexts); + + $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)['cacheable_metadata']->getCacheTags(); + $this->assertCacheTags(Cache::mergeTags($cache_context_tags, [ + 'config:views.view.frontpage', + 'node:1', 'node_list', + 'node_view', + 'user:3', + ])); $raw = '' . $this->node->url('canonical', array('fragment' => 'comments', 'absolute' => TRUE)) . ''; $this->assertRaw($raw, 'Comments as part of RSS feed.'); only in patch2: unchanged: --- a/core/modules/field/src/Tests/EntityReference/EntityReferenceFormatterTest.php +++ b/core/modules/field/src/Tests/EntityReference/EntityReferenceFormatterTest.php @@ -203,7 +203,8 @@ public function testEntityFormatter() { $expected_cache_tags = Cache::mergeTags( \Drupal::entityManager()->getViewBuilder($this->entityType)->getCacheTags(), $this->referencedEntity->getCacheTags(), - FilterFormat::load('full_html')->getCacheTags() + FilterFormat::load('full_html')->getCacheTags(), + ['config:user.role.anonymous'] ); $this->assertEqual($build[0]['#cache']['tags'], $expected_cache_tags, format_string('The @formatter formatter has the expected cache tags.', array('@formatter' => $formatter))); only in patch2: unchanged: --- a/core/modules/node/src/Tests/Views/FrontPageTest.php +++ b/core/modules/node/src/Tests/Views/FrontPageTest.php @@ -251,6 +251,8 @@ protected function assertFrontPageViewCacheTags($do_assert_views_caches) { 'url.query_args.pagers:0', ]; + $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)['cacheable_metadata']->getCacheTags(); + // Test before there are any nodes. $empty_node_listing_cache_tags = [ 'config:views.view.frontpage', @@ -260,12 +262,12 @@ protected function assertFrontPageViewCacheTags($do_assert_views_caches) { $view, $empty_node_listing_cache_tags, $do_assert_views_caches, - $empty_node_listing_cache_tags + Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags) ); $this->assertPageCacheContextsAndTags( Url::fromRoute('view.frontpage.page_1'), $cache_contexts, - Cache::mergeTags($empty_node_listing_cache_tags, ['rendered', 'config:user.role.anonymous']) + Cache::mergeTags($empty_node_listing_cache_tags, $cache_context_tags, ['rendered', 'config:user.role.anonymous']) ); // Create some nodes on the frontpage view. Add more than 10 nodes in order @@ -307,12 +309,17 @@ protected function assertFrontPageViewCacheTags($do_assert_views_caches) { 'node:14', 'node:15', ]; - $first_page_output_cache_tags = Cache::mergeTags($first_page_result_cache_tags, [ - 'config:filter.format.plain_text', - 'node_view', - 'user_view', - 'user:0', - ]); + $cache_context_tags = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)['cacheable_metadata']->getCacheTags(); + $first_page_output_cache_tags = Cache::mergeTags( + $first_page_result_cache_tags, + $cache_context_tags, + [ + 'config:filter.format.plain_text', + 'node_view', + 'user_view', + 'user:0', + ] + ); $view->setDisplay('page_1'); $view->setCurrentPage(0); $this->assertViewsCacheTags( only in patch2: unchanged: --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -349,6 +349,9 @@ public function testReferencedEntity() { ->getCacheTags(); } + $context_metadata = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($entity_cache_contexts)['cacheable_metadata']; + $cache_context_tags = $context_metadata->getCacheTags(); + // Generate the cache tags for the (non) referencing entities. $referencing_entity_cache_tags = Cache::mergeTags( $this->referencingEntity->getCacheTags(), @@ -357,6 +360,7 @@ public function testReferencedEntity() { $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntity($this->entity), $view_cache_tag, + $cache_context_tags, ['rendered'] ); $non_referencing_entity_cache_tags = Cache::mergeTags( @@ -389,7 +393,10 @@ public function testReferencedEntity() { $access_cache_contexts = $this->getAccessCacheContextsForEntity($this->entity); $redirected_cid = NULL; if (count($access_cache_contexts)) { - $redirected_cid = $this->createCacheId($cache_keys, Cache::mergeContexts($entity_cache_contexts, $this->getAdditionalCacheContextsForEntity($this->referencingEntity), $access_cache_contexts)); + $cache_contexts = Cache::mergeContexts($entity_cache_contexts, $this->getAdditionalCacheContextsForEntity($this->referencingEntity), $access_cache_contexts); + $redirected_cid = $this->createCacheId($cache_keys, $cache_contexts); + $context_metadata = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts)['cacheable_metadata']; + $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $context_metadata->getCacheTags()); } $this->verifyRenderCache($cid, $referencing_entity_cache_tags, $redirected_cid); @@ -653,7 +660,7 @@ protected function createCacheId(array $keys, array $contexts) { $cid_parts = $keys; $contexts = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($contexts); - $cid_parts = array_merge($cid_parts, $contexts); + $cid_parts = array_merge($cid_parts, $contexts['contexts']); return implode(':', $cid_parts); } only in patch2: unchanged: --- a/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php +++ b/core/modules/system/src/Tests/Entity/EntityViewBuilderTest.php @@ -65,7 +65,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_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])['contexts']); $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; @@ -117,7 +117,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_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])['contexts']); $cid_reference = implode(':', $cid_parts); $bin_reference = $build['#cache']['bin']; @@ -136,7 +136,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_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])); + $cid_parts = array_merge($build['#cache']['keys'], $cache_contexts_manager->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme'])['contexts']); $cid = implode(':', $cid_parts); $bin = $build['#cache']['bin']; only in patch2: unchanged: --- a/core/modules/system/tests/modules/pager_test/src/Controller/PagerTestController.php +++ b/core/modules/system/tests/modules/pager_test/src/Controller/PagerTestController.php @@ -69,7 +69,7 @@ public function queryParameters() { * #pre_render callback for #type => pager that shows the pager cache context. */ public static function showPagerCacheContext(array $pager) { - drupal_set_message(\Drupal::service('cache_contexts_manager')->convertTokensToKeys(['url.query_args.pagers:' . $pager['#element']])[0]); + drupal_set_message(\Drupal::service('cache_contexts_manager')->convertTokensToKeys(['url.query_args.pagers:' . $pager['#element']])['contexts'][0]); return $pager; } only in patch2: unchanged: --- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php @@ -8,6 +8,7 @@ namespace Drupal\Tests\Core\Render; use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\MemoryBackend; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Render\Element; @@ -124,7 +125,7 @@ protected function setUp() { $keys[] = $context_id; } } - return $keys; + return ['contexts' => $keys, 'cacheable_metadata' => new CacheableMetadata()]; }); $this->renderCache = new RenderCache($this->requestStack, $this->cacheFactory, $this->cacheContextsManager); $this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->renderCache, $this->rendererConfig);