.../Drupal/Core/EventSubscriber/MainContentViewSubscriber.php | 11 ++++++++++- core/modules/comment/src/Tests/CommentTranslationUITest.php | 1 + .../src/Tests/ContentTranslationUITestBase.php | 2 +- .../src/Tests/MenuLinkContentTranslationUITest.php | 2 +- core/modules/node/src/Tests/NodeBlockFunctionalTest.php | 11 ++++++----- core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php | 2 +- .../system/src/Tests/Entity/EntityCacheTagsTestBase.php | 6 ++++-- core/modules/system/src/Tests/Routing/RouterTest.php | 4 +++- core/modules/system/src/Tests/System/TokenReplaceWebTest.php | 5 +++-- core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php | 2 ++ core/modules/tracker/src/Tests/TrackerTest.php | 8 ++++---- 11 files changed, 36 insertions(+), 18 deletions(-) diff --git a/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php index 07dce6e..d1d44d6 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php @@ -7,6 +7,8 @@ namespace Drupal\Core\EventSubscriber; +use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\Cache\CacheableResponseInterface; use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Routing\RouteMatchInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -90,7 +92,14 @@ public function onViewRenderArray(GetResponseForControllerResultEvent $event) { $wrapper = isset($this->mainContentRenderers[$wrapper]) ? $wrapper : 'html'; $renderer = $this->classResolver->getInstanceFromDefinition($this->mainContentRenderers[$wrapper]); - $event->setResponse($renderer->renderResponse($result, $request, $this->routeMatch)); + $response = $renderer->renderResponse($result, $request, $this->routeMatch); + // The main content render array is rendered into a different Response + // object, depending on the specified wrapper format. + if ($response instanceof CacheableResponseInterface) { + $main_content_view_subscriber_cacheability = (new CacheableMetadata())->setCacheContexts(['url.query_args:' . static::WRAPPER_FORMAT]); + $response->addCacheableDependency($main_content_view_subscriber_cacheability); + } + $event->setResponse($response); } } diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php index f7b508a..6397c69 100644 --- a/core/modules/comment/src/Tests/CommentTranslationUITest.php +++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php @@ -39,6 +39,7 @@ class CommentTranslationUITest extends ContentTranslationUITestBase { 'languages:language_interface', 'theme', 'timezone', + 'url.query_args:_wrapper_format', 'url.query_args.pagers:0', 'user' ]; diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php index 0c6b635..a5d6d09 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php @@ -52,7 +52,7 @@ * * @var string[] */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user.permissions']; + protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.query_args:_wrapper_format', 'user.permissions']; /** * Tests the basic translation UI. diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php index 615da6b..f72cb29 100644 --- a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php +++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php @@ -20,7 +20,7 @@ class MenuLinkContentTranslationUITest extends ContentTranslationUITestBase { /** * {inheritdoc} */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user.permissions', 'user.roles:authenticated']; + protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.query_args:_wrapper_format', 'user.permissions', 'user.roles:authenticated']; /** * Modules to enable. diff --git a/core/modules/node/src/Tests/NodeBlockFunctionalTest.php b/core/modules/node/src/Tests/NodeBlockFunctionalTest.php index 06b83cd..6f319f5 100644 --- a/core/modules/node/src/Tests/NodeBlockFunctionalTest.php +++ b/core/modules/node/src/Tests/NodeBlockFunctionalTest.php @@ -8,6 +8,7 @@ namespace Drupal\node\Tests; use Drupal\block\Entity\Block; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; use Drupal\user\RoleInterface; @@ -119,7 +120,7 @@ public function testRecentNodeBlock() { $this->assertText($node3->label(), 'Node found in block.'); $this->assertText($node4->label(), 'Node found in block.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'user']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); // Enable the "Powered by Drupal" block only on article nodes. $edit = [ @@ -144,16 +145,16 @@ public function testRecentNodeBlock() { $this->drupalGet(''); $label = $block->label(); $this->assertNoText($label, 'Block was not displayed on the front page.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'user', 'route']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route']); $this->drupalGet('node/add/article'); $this->assertText($label, 'Block was displayed on the node/add/article page.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'user', 'route']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route']); $this->drupalGet('node/' . $node1->id()); $this->assertText($label, 'Block was displayed on the node/N when node is of type article.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'user', 'route', 'timezone']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route', 'timezone']); $this->drupalGet('node/' . $node5->id()); $this->assertNoText($label, 'Block was not displayed on nodes of type page.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'user', 'route', 'timezone']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route', 'timezone']); $this->drupalLogin($this->adminUser); $this->drupalGet('admin/structure/block'); diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php index 9a9113b..5fa63d8 100644 --- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php +++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php @@ -21,7 +21,7 @@ class ShortcutTranslationUITest extends ContentTranslationUITestBase { /** * {inheritdoc} */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user', 'url.site']; + protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user', 'url.query_args:_wrapper_format', 'url.site']; /** * Modules to enable. diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index 8f10556..ee4fcd8 100644 --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Url; @@ -337,6 +338,7 @@ public function testReferencedEntity() { // The default cache contexts for rendered entities. $default_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; $entity_cache_contexts = $default_cache_contexts; + $page_cache_contexts = Cache::mergeContexts($default_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); // Cache tags present on every rendered page. // 'user.permissions' is a required cache context, and responses that vary @@ -428,7 +430,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(Cache::mergeContexts($default_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); + $this->assertEqual(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); $this->pass("Test listing containing referenced entity.", 'Debug'); @@ -438,7 +440,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(Cache::mergeContexts($default_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header)); + $this->assertEqual(Cache::mergeContexts($page_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/Routing/RouterTest.php b/core/modules/system/src/Tests/Routing/RouterTest.php index 9f6e8c8..4d532d1 100644 --- a/core/modules/system/src/Tests/Routing/RouterTest.php +++ b/core/modules/system/src/Tests/Routing/RouterTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Routing; use Drupal\Core\Cache\Cache; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Language\LanguageInterface; use Drupal\simpletest\WebTestBase; use Symfony\Component\HttpFoundation\Request; @@ -32,6 +33,7 @@ class RouterTest extends WebTestBase { */ public function testFinishResponseSubscriber() { $renderer_required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; + $expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); // Confirm that the router can get to a controller. $this->drupalGet('router_test/test1'); @@ -47,7 +49,7 @@ public function testFinishResponseSubscriber() { $this->assertRaw('test2', 'The correct string was returned because the route was successful.'); // Check expected headers from FinishResponseSubscriber. $headers = $this->drupalGetHeaders(); - $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $renderer_required_cache_contexts)); + $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $expected_cache_contexts)); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous rendered'); // Confirm that the page wrapping is being added, so we're not getting a // raw body returned. diff --git a/core/modules/system/src/Tests/System/TokenReplaceWebTest.php b/core/modules/system/src/Tests/System/TokenReplaceWebTest.php index 7e9d60f..ba94e51 100644 --- a/core/modules/system/src/Tests/System/TokenReplaceWebTest.php +++ b/core/modules/system/src/Tests/System/TokenReplaceWebTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\System; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\simpletest\WebTestBase; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; @@ -35,12 +36,12 @@ public function testTokens() { $this->drupalGet('token-test/' . $node->id()); $this->assertText("Tokens: {$node->id()} {$account->id()}"); $this->assertCacheTags(['node:1', 'rendered', 'user:2']); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'user']); + $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); $this->drupalGet('token-test-without-bubleable-metadata/' . $node->id()); $this->assertText("Tokens: {$node->id()} {$account->id()}"); $this->assertCacheTags(['node:1', 'rendered', 'user:2']); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'user']); + $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); } } diff --git a/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php b/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php index 277d312..759f646 100644 --- a/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php +++ b/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php @@ -8,6 +8,7 @@ namespace Drupal\toolbar\Tests; use Drupal\Core\Cache\Cache; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\simpletest\WebTestBase; use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait; @@ -109,6 +110,7 @@ protected function assertToolbarCacheContexts(array $cache_contexts, $message = $default_cache_contexts = [ 'languages:language_interface', 'theme', + 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, ]; $cache_contexts = Cache::mergeContexts($default_cache_contexts, $cache_contexts); diff --git a/core/modules/tracker/src/Tests/TrackerTest.php b/core/modules/tracker/src/Tests/TrackerTest.php index c57f1c9..d1fc792 100644 --- a/core/modules/tracker/src/Tests/TrackerTest.php +++ b/core/modules/tracker/src/Tests/TrackerTest.php @@ -10,6 +10,7 @@ use Drupal\comment\CommentInterface; use Drupal\comment\Tests\CommentTestTrait; use Drupal\Core\Cache\Cache; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Session\AccountInterface; use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; @@ -83,8 +84,7 @@ function testTrackerAll() { $this->assertLink(t('My recent content'), 0, 'User tab shows up on the global tracker page.'); // Assert cache contexts, specifically the pager and node access contexts. - $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args.pagers:0', 'user.node_grants:view', 'user.permissions']); - // Assert cache tags for the visible node and node list cache tag. + $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user.node_grants:view', 'user.permissions']); $expected_tags = Cache::mergeTags($published->getCacheTags(), $published->getOwner()->getCacheTags()); $expected_tags = Cache::mergeTags($expected_tags, ['node_list', 'rendered']); $this->assertCacheTags($expected_tags); @@ -149,7 +149,7 @@ function testTrackerUser() { $this->assertText($other_published_my_comment->label(), "Nodes that the user has commented on appear in the user's tracker listing."); // Assert cache contexts. - $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); + $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); // Assert cache tags for the visible nodes (including owners) and node list // cache tag. $expected_tags = Cache::mergeTags($my_published->getCacheTags(), $my_published->getOwner()->getCacheTags()); @@ -158,7 +158,7 @@ function testTrackerUser() { $expected_tags = Cache::mergeTags($expected_tags, ['node_list', 'rendered']); $this->assertCacheTags($expected_tags); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); + $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); $this->assertLink($my_published->label()); $this->assertNoLink($unpublished->label());