public function RendererPlaceholdersTest::testCacheableParent in Drupal 10
Same name and namespace in other branches
- 8 core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php \Drupal\Tests\Core\Render\RendererPlaceholdersTest::testCacheableParent()
- 9 core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php \Drupal\Tests\Core\Render\RendererPlaceholdersTest::testCacheableParent()
@covers ::render @covers ::doRender @covers \Drupal\Core\Render\RenderCache::get @covers \Drupal\Core\Render\RenderCache::set @covers \Drupal\Core\Render\RenderCache::createCacheID
@dataProvider providerPlaceholders
File
- core/
tests/ Drupal/ Tests/ Core/ Render/ RendererPlaceholdersTest.php, line 620 - Contains \Drupal\Tests\Core\Render\RendererPlaceholdersTest.
Class
- RendererPlaceholdersTest
- @coversDefaultClass \Drupal\Core\Render\Renderer @covers \Drupal\Core\Render\RenderCache @covers \Drupal\Core\Render\PlaceholderingRenderCache @group Render
Namespace
Drupal\Tests\Core\RenderCode
public function testCacheableParent($test_element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $bubbled_cache_contexts, array $bubbled_cache_tags, array $placeholder_expected_render_cache_array) {
$element = $test_element;
$this
->setupMemoryCache();
$this
->setUpRequest('GET');
$token = Crypt::hashBase64(serialize($expected_placeholder_render_array));
$placeholder_callback = $expected_placeholder_render_array['#lazy_builder'][0];
$expected_placeholder_markup = '<drupal-render-placeholder callback="' . $placeholder_callback . '" arguments="0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>';
$this
->assertSame($expected_placeholder_markup, Html::normalize($expected_placeholder_markup), 'Placeholder unaltered by Html::normalize() which is used by FilterHtmlCorrector.');
// GET request: #cache enabled, cache miss.
$element['#cache'] = [
'keys' => [
'placeholder_test_GET',
],
];
$element['#prefix'] = '<p>#cache enabled, GET</p>';
$output = $this->renderer
->renderRoot($element);
$this
->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this
->assertTrue(isset($element['#printed']), 'No cache hit');
$this
->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
];
$this
->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
$this
->assertPlaceholderRenderCache($placeholder_cid_parts, $bubbled_cache_contexts, $placeholder_expected_render_cache_array);
// GET request: validate cached data.
$cached = $this->memoryCache
->get('placeholder_test_GET');
// There are three edge cases, where the shape of the render cache item for
// the parent (with CID 'placeholder_test_GET') is vastly different. These
// are the cases where:
// - the placeholder is uncacheable (because it has no #cache[keys]), and;
// - cacheability metadata that meets auto_placeholder_conditions is bubbled
$has_uncacheable_lazy_builder = !isset($test_element['placeholder']['#cache']['keys']) && isset($test_element['placeholder']['#lazy_builder']);
// Edge cases: always where both bubbling of an auto-placeholdering
// condition happens from within a #lazy_builder that is uncacheable.
// - uncacheable + A5 (cache max-age)
// @todo in https://www.drupal.org/node/2559847
// - uncacheable + A6 (cache context)
$edge_case_a6_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\\Tests\\Core\\Render\\PlaceholdersTest::callbackPerUser';
// - uncacheable + A7 (cache tag)
$edge_case_a7_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\\Tests\\Core\\Render\\PlaceholdersTest::callbackTagCurrentTemperature';
// The redirect-cacheable edge case: a high-cardinality cache context is
// bubbled from a #lazy_builder callback for an uncacheable placeholder. The
// element containing the uncacheable placeholder has cache keys set, and
// due to the bubbled cache contexts it creates a cache redirect.
if ($edge_case_a6_uncacheable) {
$cached_element = $cached->data;
$expected_redirect = [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => [
'placeholder_test_GET',
],
'contexts' => [
'user',
],
'tags' => [],
'max-age' => Cache::PERMANENT,
'bin' => 'render',
],
];
$this
->assertEquals($expected_redirect, $cached_element);
// Follow the redirect.
$cached_element = $this->memoryCache
->get('placeholder_test_GET:' . implode(':', $bubbled_cache_contexts))->data;
$expected_element = [
'#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
'dynamic_animal' => $args[0],
],
],
'#cache' => [
'contexts' => $bubbled_cache_contexts,
'tags' => [],
'max-age' => Cache::PERMANENT,
],
];
$this
->assertEquals($expected_element, $cached_element, 'The parent is render cached with a redirect in ase a cache context is bubbled from an uncacheable child (no #cache[keys]) with a #lazy_builder.');
}
elseif ($edge_case_a7_uncacheable) {
$cached_element = $cached->data;
$expected_element = [
'#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
'dynamic_animal' => $args[0],
],
],
'#cache' => [
'contexts' => [],
'tags' => $bubbled_cache_tags,
'max-age' => Cache::PERMANENT,
],
];
$this
->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
}
else {
$cached_element = $cached->data;
$expected_element = [
'#markup' => '<p>#cache enabled, GET</p>' . $expected_placeholder_markup,
'#attached' => [
'drupalSettings' => [
'foo' => 'bar',
],
'placeholders' => [
$expected_placeholder_markup => [
'#lazy_builder' => [
'Drupal\\Tests\\Core\\Render\\PlaceholdersTest::callback',
$args,
],
],
],
],
'#cache' => [
'contexts' => [],
'tags' => $bubbled_cache_tags,
'max-age' => Cache::PERMANENT,
],
];
$expected_element['#attached']['placeholders'][$expected_placeholder_markup] = $expected_placeholder_render_array;
$this
->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
}
// GET request: #cache enabled, cache hit.
$element = $test_element;
$element['#cache'] = [
'keys' => [
'placeholder_test_GET',
],
];
$element['#prefix'] = '<p>#cache enabled, GET</p>';
$output = $this->renderer
->renderRoot($element);
$this
->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this
->assertFalse(isset($element['#printed']), 'Cache hit');
$this
->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
];
$this
->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
}