diff --git a/core/lib/Drupal/Core/Render/RenderCache.php b/core/lib/Drupal/Core/Render/RenderCache.php index aa071cc9be05f9320bda762a0e26d44db3300231..922d3a6595b495f8f06323658c0033279e78dd9c 100644 --- a/core/lib/Drupal/Core/Render/RenderCache.php +++ b/core/lib/Drupal/Core/Render/RenderCache.php @@ -237,6 +237,8 @@ public function set(array &$elements, array $pre_bubbling_elements) { 'contexts' => $merged_cache_contexts, // The union of the current element's and stored cache tags. 'tags' => Cache::mergeTags($stored_cache_tags, $data['#cache']['tags']), + // The same cache bin as the one for the actual render cache items. + 'bin' => $bin, ], ]; $cache->set($pre_bubbling_cid, $redirect_data, $expire, Cache::mergeTags($redirect_data['#cache']['tags'], ['rendered'])); diff --git a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php index 5389b021f8a44aa3ef79baf49002dc03003a6b81..405c4ef789edbf287ba0ff85ddaadc409afd13e9 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Core\Render; +use Drupal\Core\Cache\MemoryBackend; use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; use Drupal\Core\Render\Element; use Drupal\Core\Render\Renderer; @@ -28,15 +29,15 @@ protected function setUp() { $this->rendererConfig['required_cache_contexts'] = []; parent::setUp(); - - $this->setUpRequest(); - $this->setupMemoryCache(); } /** * Tests bubbling of assets when NOT using #pre_render callbacks. */ public function testBubblingWithoutPreRender() { + $this->setUpRequest(); + $this->setupMemoryCache(); + $this->elementInfo->expects($this->any()) ->method('getInfo') ->willReturn([]); @@ -76,6 +77,58 @@ public function testBubblingWithoutPreRender() { $this->assertEquals($element['#attached']['library'], $expected_libraries, 'The element, child and subchild #attached libraries are included.'); } + /** + * Tests cache context bubbling with a custom cache bin. + */ + public function testContextBubblingCustomCacheBin() { + $bin = $this->randomMachineName(); + + $this->setUpRequest(); + $this->memoryCache = new MemoryBackend('render'); + $custom_cache = new MemoryBackend($bin); + + $this->cacheFactory->expects($this->atLeastOnce()) + ->method('get') + ->with($bin) + ->willReturnCallback(function($requested_bin) use ($bin, $custom_cache) { + if ($requested_bin === $bin) { + return $custom_cache; + } + else { + throw new \Exception(); + } + }); + $this->cacheContextsManager->expects($this->any()) + ->method('convertTokensToKeys') + ->willReturnArgument(0); + + $build = [ + '#cache' => [ + 'keys' => ['parent'], + 'contexts' => ['foo'], + 'bin' => $bin, + ], + '#markup' => 'parent', + 'child' => [ + '#cache' => [ + 'contexts' => ['bar'], + 'max-age' => 3600, + ], + ], + ]; + $this->renderer->render($build); + + $this->assertRenderCacheItem('parent:foo', [ + '#cache_redirect' => TRUE, + '#cache' => [ + 'keys' => ['parent'], + 'contexts' => ['bar', 'foo'], + 'tags' => [], + 'bin' => $bin, + ], + ], $bin); + } + /** * Tests cache context bubbling in edge cases, because it affects the CID. * @@ -228,6 +281,7 @@ public function providerTestContextBubblingEdgeCases() { 'keys' => ['parent'], 'contexts' => ['bar', 'foo'], 'tags' => ['dee', 'fiddle', 'har', 'yar'], + 'bin' => 'render', ], ], 'parent:bar:foo' => [ @@ -302,6 +356,7 @@ public function testConditionalCacheContextBubblingSelfHealing() { 'keys' => ['parent'], 'contexts' => ['user.roles'], 'tags' => ['a', 'b'], + 'bin' => 'render', ], ]); $this->assertRenderCacheItem('parent:r.A', [ @@ -326,6 +381,7 @@ public function testConditionalCacheContextBubblingSelfHealing() { 'keys' => ['parent'], 'contexts' => ['foo', 'user.roles'], 'tags' => ['a', 'b', 'c'], + 'bin' => 'render', ], ]); $this->assertRenderCacheItem('parent:foo:r.B', [ @@ -358,6 +414,7 @@ public function testConditionalCacheContextBubblingSelfHealing() { 'keys' => ['parent'], 'contexts' => ['foo', 'user.roles'], 'tags' => ['a', 'b', 'c'], + 'bin' => 'render', ], ]); $this->assertRenderCacheItem('parent:foo:r.A', [ @@ -382,6 +439,7 @@ public function testConditionalCacheContextBubblingSelfHealing() { 'keys' => ['parent'], 'contexts' => ['bar', 'foo', 'user.roles'], 'tags' => ['a', 'b', 'c', 'd'], + 'bin' => 'render', ], ]; $this->assertRenderCacheItem('parent', $final_parent_cache_item); @@ -435,6 +493,9 @@ public function testConditionalCacheContextBubblingSelfHealing() { * @dataProvider providerTestBubblingWithPrerender */ public function testBubblingWithPrerender($test_element) { + $this->setUpRequest(); + $this->setupMemoryCache(); + // Mock the State service. $memory_state = new State(new KeyValueMemoryFactory());; \Drupal::getContainer()->set('state', $memory_state); diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php index 0a8a28ab46da0c593e1d65f59f104118467ec9af..19772a361946d361f7b58a09cebbea68394e3b15 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php @@ -172,6 +172,7 @@ protected function setupMemoryCache() { $this->cacheFactory->expects($this->atLeastOnce()) ->method('get') + ->with('render') ->willReturn($this->memoryCache); } @@ -195,9 +196,12 @@ protected function setUpRequest($method = 'GET') { * The expected cache ID. * @param mixed $data * The expected data for that cache ID. + * @param string $bin + * The expected cache bin. */ - protected function assertRenderCacheItem($cid, $data) { - $cached = $this->memoryCache->get($cid); + protected function assertRenderCacheItem($cid, $data, $bin = 'render') { + $cache_backend = $this->cacheFactory->get($bin); + $cached = $cache_backend->get($cid); $this->assertNotFalse($cached, sprintf('Expected cache item "%s" exists.', $cid)); if ($cached !== FALSE) { $this->assertEquals($data, $cached->data, sprintf('Cache item "%s" has the expected data.', $cid));