View source
<?php
namespace Drupal\Tests\block\Kernel;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\LanguageInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\block\Entity\Block;
class BlockViewBuilderTest extends KernelTestBase {
protected static $modules = [
'block',
'block_test',
'system',
'user',
];
protected $block;
protected $controller;
protected $renderer;
protected function setUp() : void {
parent::setUp();
$this->controller = $this->container
->get('entity_type.manager')
->getStorage('block');
\Drupal::state()
->set('block_test.content', 'Llamas > unicorns!');
$this->block = $this->controller
->create([
'id' => 'test_block',
'theme' => 'stark',
'plugin' => 'test_cache',
]);
$this->block
->save();
$this->container
->get('cache.render')
->deleteAll();
$this->renderer = $this->container
->get('renderer');
}
public function testBasicRendering() {
\Drupal::state()
->set('block_test.content', '');
$entity = $this->controller
->create([
'id' => 'test_block1',
'theme' => 'stark',
'plugin' => 'test_html',
]);
$entity
->save();
$entity = Block::load('test_block1');
$builder = \Drupal::entityTypeManager()
->getViewBuilder('block');
$output = $builder
->view($entity, 'block');
$expected = [];
$expected[] = '<div id="block-test-block1">';
$expected[] = ' ';
$expected[] = ' ';
$expected[] = ' ';
$expected[] = ' </div>';
$expected[] = '';
$expected_output = implode("\n", $expected);
$this
->assertEquals($expected_output, $this->renderer
->renderRoot($output));
Html::resetSeenIds();
$entity = $this->controller
->create([
'id' => 'test_block2',
'theme' => 'stark',
'plugin' => 'test_html',
'settings' => [
'label' => 'Powered by Bananas',
],
]);
$entity
->save();
$output = $builder
->view($entity, 'block');
$expected = [];
$expected[] = '<div id="block-test-block2">';
$expected[] = ' ';
$expected[] = ' <h2>Powered by Bananas</h2>';
$expected[] = ' ';
$expected[] = ' ';
$expected[] = ' </div>';
$expected[] = '';
$expected_output = implode("\n", $expected);
$this
->assertEquals($expected_output, $this->renderer
->renderRoot($output));
}
public function testBlockViewBuilderCache() {
$this
->verifyRenderCacheHandling();
$this->block = $this->controller
->create([
'id' => 'test_block',
'theme' => 'stark',
'plugin' => 'test_cache',
]);
$this->block
->save();
\Drupal::state()
->set('block_test.content', NULL);
$this
->verifyRenderCacheHandling();
}
protected function verifyRenderCacheHandling() {
$request = \Drupal::request();
$request_method = $request->server
->get('REQUEST_METHOD');
$request
->setMethod('GET');
$build = $this
->getBlockRenderArray();
$cid = 'entity_view:block:test_block:' . implode(':', \Drupal::service('cache_contexts_manager')
->convertTokensToKeys([
'languages:' . LanguageInterface::TYPE_INTERFACE,
'theme',
'user.permissions',
])
->getKeys());
$this->renderer
->renderRoot($build);
$this
->assertNotEmpty($this->container
->get('cache.render')
->get($cid), 'The block render element has been cached.');
$this->block
->save();
$this
->assertFalse($this->container
->get('cache.render')
->get($cid), 'The block render cache entry has been cleared when the block was saved.');
unset($build['#printed']);
$build['#block'] = $this->block;
$this->renderer
->renderRoot($build);
$this
->assertNotEmpty($this->container
->get('cache.render')
->get($cid), 'The block render element has been cached.');
$this->block
->delete();
$this
->assertFalse($this->container
->get('cache.render')
->get($cid), 'The block render cache entry has been cleared when the block was deleted.');
$request
->setMethod($request_method);
}
public function testBlockViewBuilderViewAlter() {
$build = $this
->getBlockRenderArray();
$this
->setRawContent((string) $this->renderer
->renderRoot($build));
$this
->assertSame('Llamas > unicorns!', trim((string) $this
->cssSelect('div')[0]));
\Drupal::state()
->set('block_test_view_alter_suffix', TRUE);
Cache::invalidateTags($this->block
->getCacheTagsToInvalidate());
$build = $this
->getBlockRenderArray();
$this
->setRawContent((string) $this->renderer
->renderRoot($build));
$this
->assertSame('Llamas > unicorns!', trim((string) $this
->cssSelect('[foo=bar]')[0]));
\Drupal::state()
->set('block_test_view_alter_suffix', FALSE);
\Drupal::state()
->set('block_test.content', NULL);
Cache::invalidateTags($this->block
->getCacheTagsToInvalidate());
\Drupal::state()
->set('block_test_view_alter_append_pre_render_prefix', TRUE);
$build = $this
->getBlockRenderArray();
$this
->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
$this
->assertSame('Hiya!<br>', (string) $this->renderer
->renderRoot($build));
$this
->assertArrayHasKey('#prefix', $build);
$this
->assertSame('Hiya!<br>', $build['#prefix']);
}
public function testBlockViewBuilderBuildAlter() {
$request = \Drupal::request();
$request_method = $request->server
->get('REQUEST_METHOD');
$request
->setMethod('GET');
$default_keys = [
'entity_view',
'block',
'test_block',
];
$default_contexts = [];
$default_tags = [
'block_view',
'config:block.block.test_block',
];
$default_max_age = Cache::PERMANENT;
$alter_add_key = $this
->randomMachineName();
\Drupal::state()
->set('block_test_block_alter_cache_key', $alter_add_key);
$this
->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [
$alter_add_key,
]), $default_contexts, $default_tags, $default_max_age);
\Drupal::state()
->set('block_test_block_alter_cache_key', NULL);
$alter_add_context = 'url.query_args:' . $this
->randomMachineName();
\Drupal::state()
->set('block_test_block_alter_cache_context', $alter_add_context);
$this
->assertBlockRenderedWithExpectedCacheability($default_keys, Cache::mergeContexts($default_contexts, [
$alter_add_context,
]), $default_tags, $default_max_age);
\Drupal::state()
->set('block_test_block_alter_cache_context', NULL);
$alter_add_tag = $this
->randomMachineName();
\Drupal::state()
->set('block_test_block_alter_cache_tag', $alter_add_tag);
$this
->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, Cache::mergeTags($default_tags, [
$alter_add_tag,
]), $default_max_age);
\Drupal::state()
->set('block_test_block_alter_cache_tag', NULL);
$alter_max_age = 300;
\Drupal::state()
->set('block_test_block_alter_cache_max_age', $alter_max_age);
$this
->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, $default_tags, $alter_max_age);
\Drupal::state()
->set('block_test_block_alter_cache_max_age', NULL);
\Drupal::state()
->set('block_test_block_alter_cache_key', $alter_add_key);
\Drupal::state()
->set('block_test_block_alter_cache_context', $alter_add_context);
\Drupal::state()
->set('block_test_block_alter_cache_tag', $alter_add_tag);
\Drupal::state()
->set('block_test_block_alter_cache_max_age', $alter_max_age);
$this
->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [
$alter_add_key,
]), Cache::mergeContexts($default_contexts, [
$alter_add_context,
]), Cache::mergeTags($default_tags, [
$alter_add_tag,
]), $alter_max_age);
\Drupal::state()
->set('block_test_block_alter_cache_key', NULL);
\Drupal::state()
->set('block_test_block_alter_cache_context', NULL);
\Drupal::state()
->set('block_test_block_alter_cache_tag', NULL);
\Drupal::state()
->set('block_test_block_alter_cache_max_age', NULL);
foreach ([
TRUE,
FALSE,
] as $value) {
\Drupal::state()
->set('block_test_block_alter_create_placeholder', $value);
$build = $this
->getBlockRenderArray();
$this
->assertTrue(isset($build['#create_placeholder']));
$this
->assertSame($value, $build['#create_placeholder']);
}
\Drupal::state()
->set('block_test_block_alter_create_placeholder', NULL);
$request
->setMethod($request_method);
}
protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, int $expected_max_age) : void {
$required_cache_contexts = [
'languages:' . LanguageInterface::TYPE_INTERFACE,
'theme',
'user.permissions',
];
$build = $this
->getBlockRenderArray();
$this
->assertSame($expected_keys, $build['#cache']['keys']);
$this
->assertEqualsCanonicalizing($expected_contexts, $build['#cache']['contexts']);
$this
->assertEqualsCanonicalizing($expected_tags, $build['#cache']['tags']);
$this
->assertSame($expected_max_age, $build['#cache']['max-age']);
$this
->assertFalse(isset($build['#create_placeholder']));
$this->renderer
->renderRoot($build);
$final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
$cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')
->convertTokensToKeys($final_cache_contexts)
->getKeys());
$cache_item = $this->container
->get('cache.render')
->get($cid);
$this
->assertNotEmpty($cache_item, 'The block render element has been cached with the expected cache ID.');
$this
->assertEqualsCanonicalizing(Cache::mergeTags($expected_tags, [
'rendered',
]), $cache_item->tags);
$this
->assertEqualsCanonicalizing($final_cache_contexts, $cache_item->data['#cache']['contexts']);
$this
->assertEqualsCanonicalizing($expected_tags, $cache_item->data['#cache']['tags']);
$this
->assertSame($expected_max_age, $cache_item->data['#cache']['max-age']);
$this->container
->get('cache.render')
->delete($cid);
}
protected function getBlockRenderArray() {
return $this->container
->get('entity_type.manager')
->getViewBuilder('block')
->view($this->block, 'block');
}
}