function RendererBubblingTest::testConditionalCacheContextBubblingSelfHealing
Same name in other branches
- 8.9.x core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php \Drupal\Tests\Core\Render\RendererBubblingTest::testConditionalCacheContextBubblingSelfHealing()
- 10 core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php \Drupal\Tests\Core\Render\RendererBubblingTest::testConditionalCacheContextBubblingSelfHealing()
- 11.x core/tests/Drupal/Tests/Core/Render/RendererBubblingTest.php \Drupal\Tests\Core\Render\RendererBubblingTest::testConditionalCacheContextBubblingSelfHealing()
Tests the self-healing of the redirect with conditional cache contexts.
File
-
core/
tests/ Drupal/ Tests/ Core/ Render/ RendererBubblingTest.php, line 336
Class
- RendererBubblingTest
- @coversDefaultClass \Drupal\Core\Render\Renderer @group Render
Namespace
Drupal\Tests\Core\RenderCode
public function testConditionalCacheContextBubblingSelfHealing() {
$current_user_role =& $this->currentUserRole;
$this->setUpRequest();
$this->setupMemoryCache();
$test_element = [
'#cache' => [
'keys' => [
'parent',
],
'tags' => [
'a',
],
],
'#markup' => 'parent',
'child' => [
'#cache' => [
'contexts' => [
'user.roles',
],
'tags' => [
'b',
],
],
'grandchild' => [
'#access_callback' => function () use (&$current_user_role) {
// Only role A cannot access this subtree.
return $current_user_role !== 'A';
},
'#cache' => [
'contexts' => [
'foo',
],
'tags' => [
'c',
],
// A lower max-age; the redirecting cache item should be updated.
'max-age' => 1800,
],
'grandgrandchild' => [
'#access_callback' => function () use (&$current_user_role) {
// Only role C can access this subtree.
return $current_user_role === 'C';
},
'#cache' => [
'contexts' => [
'bar',
],
'tags' => [
'd',
],
// A lower max-age; the redirecting cache item should be updated.
'max-age' => 300,
],
],
],
],
];
// Request 1: role A, the grandchild isn't accessible => bubbled cache
// contexts: user.roles.
$element = $test_element;
$current_user_role = 'A';
$this->renderer
->renderRoot($element);
$this->assertRenderCacheItem('parent', [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => [
'parent',
],
'contexts' => [
'user.roles',
],
'tags' => [
'a',
'b',
],
'bin' => 'render',
'max-age' => Cache::PERMANENT,
],
]);
$this->assertRenderCacheItem('parent:r.A', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
],
'tags' => [
'a',
'b',
],
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
]);
// Request 2: role B, the grandchild is accessible => bubbled cache
// contexts: foo, user.roles + merged max-age: 1800.
$element = $test_element;
$current_user_role = 'B';
$this->renderer
->renderRoot($element);
$this->assertRenderCacheItem('parent', [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => [
'parent',
],
'contexts' => [
'user.roles',
'foo',
],
'tags' => [
'a',
'b',
'c',
],
'bin' => 'render',
'max-age' => 1800,
],
]);
$this->assertRenderCacheItem('parent:foo:r.B', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
'foo',
],
'tags' => [
'a',
'b',
'c',
],
'max-age' => 1800,
],
'#markup' => 'parent',
]);
// Request 3: role A again, the grandchild is inaccessible again => bubbled
// cache contexts: user.roles; but that's a subset of the already-bubbled
// cache contexts, so nothing is actually changed in the redirecting cache
// item. However, the cache item we were looking for in request 1 is
// technically the same one we're looking for now (it's the exact same
// request), but with one additional cache context. This is necessary to
// avoid "cache ping-pong". (Requests 1 and 3 are identical, but without the
// right merging logic to handle request 2, the redirecting cache item would
// toggle between only the 'user.roles' cache context and both the 'foo'
// and 'user.roles' cache contexts, resulting in a cache miss every time.)
$element = $test_element;
$current_user_role = 'A';
$this->renderer
->renderRoot($element);
$this->assertRenderCacheItem('parent', [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => [
'parent',
],
'contexts' => [
'user.roles',
'foo',
],
'tags' => [
'a',
'b',
'c',
],
'bin' => 'render',
'max-age' => 1800,
],
]);
$this->assertRenderCacheItem('parent:foo:r.A', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
'foo',
],
'tags' => [
'a',
'b',
],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
// despite 1800 being the max-age of the redirecting cache item.
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
]);
// Request 4: role C, both the grandchild and the grandgrandchild are
// accessible => bubbled cache contexts: foo, bar, user.roles + merged
// max-age: 300.
$element = $test_element;
$current_user_role = 'C';
$this->renderer
->renderRoot($element);
$final_parent_cache_item = [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => [
'parent',
],
'contexts' => [
'user.roles',
'foo',
'bar',
],
'tags' => [
'a',
'b',
'c',
'd',
],
'bin' => 'render',
'max-age' => 300,
],
];
$this->assertRenderCacheItem('parent', $final_parent_cache_item);
$this->assertRenderCacheItem('parent:bar:foo:r.C', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
'foo',
'bar',
],
'tags' => [
'a',
'b',
'c',
'd',
],
'max-age' => 300,
],
'#markup' => 'parent',
]);
// Request 5: role A again, verifying the merging like we did for request 3.
$element = $test_element;
$current_user_role = 'A';
$this->renderer
->renderRoot($element);
$this->assertRenderCacheItem('parent', $final_parent_cache_item);
$this->assertRenderCacheItem('parent:bar:foo:r.A', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
'foo',
'bar',
],
'tags' => [
'a',
'b',
],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
// nor the grandgrandchild's max-age of 300, despite 300 being the
// max-age of the redirecting cache item.
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
]);
// Request 6: role B again, verifying the merging like we did for request 3.
$element = $test_element;
$current_user_role = 'B';
$this->renderer
->renderRoot($element);
$this->assertRenderCacheItem('parent', $final_parent_cache_item);
$this->assertRenderCacheItem('parent:bar:foo:r.B', [
'#attached' => [],
'#cache' => [
'contexts' => [
'user.roles',
'foo',
'bar',
],
'tags' => [
'a',
'b',
'c',
],
// Note that the max-age here is unaffected. When role B, the
// grandgrandchild is never rendered, so neither is its max-age of 300
// present here, despite 300 being the max-age of the redirecting cache
// item.
'max-age' => 1800,
],
'#markup' => 'parent',
]);
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.