Commit 938e2f64 authored by catch's avatar catch
Browse files

Issue #2428805 by Wim Leers: Remove the ability to configure a block's cache contexts

parent 3fbe92b0
...@@ -295,12 +295,6 @@ block_settings: ...@@ -295,12 +295,6 @@ block_settings:
max_age: max_age:
type: integer type: integer
label: 'Maximum age' label: 'Maximum age'
contexts:
type: sequence
label: 'Vary by context'
sequence:
type: string
label: 'Context'
status: status:
type: boolean type: boolean
label: 'Status' label: 'Status'
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
use Drupal\block\BlockInterface; use Drupal\block\BlockInterface;
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\CacheContexts;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContextAwarePluginBase; use Drupal\Core\Plugin\ContextAwarePluginBase;
use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\Unicode;
...@@ -91,8 +90,8 @@ protected function baseConfigurationDefaults() { ...@@ -91,8 +90,8 @@ protected function baseConfigurationDefaults() {
'provider' => $this->pluginDefinition['provider'], 'provider' => $this->pluginDefinition['provider'],
'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
'cache' => array( 'cache' => array(
'max_age' => 0, // Blocks are cacheable by default.
'contexts' => array(), 'max_age' => Cache::PERMANENT,
), ),
); );
} }
...@@ -204,36 +203,6 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta ...@@ -204,36 +203,6 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
'#default_value' => $this->configuration['cache']['max_age'], '#default_value' => $this->configuration['cache']['max_age'],
'#options' => $period, '#options' => $period,
); );
$contexts = \Drupal::service("cache_contexts")->getLabels();
// Blocks are always rendered in the "per language" and "per theme" cache
// contexts. No need to show those options to the end user.
unset($contexts['languages']);
unset($contexts['theme']);
$form['cache']['contexts'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Vary by context'),
'#description' => $this->t('The contexts this cached block must be varied by. <em>All</em> blocks are varied by language and theme.'),
'#default_value' => $this->configuration['cache']['contexts'],
'#options' => $contexts,
'#states' => array(
'disabled' => array(
':input[name="settings[cache][max_age]"]' => array('value' => (string) 0),
),
),
);
if (count($this->getRequiredCacheContexts()) > 0) {
// Remove the required cache contexts from the list of contexts a user can
// choose to modify by: they must always be applied.
$context_labels = array();
$all_contexts = \Drupal::service("cache_contexts")->getLabels(TRUE);
foreach (CacheContexts::parseTokens($this->getRequiredCacheContexts()) as $context) {
$context_id = $context[0];
$context_labels[] = $all_contexts[$context_id];
unset($form['cache']['contexts']['#options'][$context_id]);
}
$required_context_list = implode(', ', $context_labels);
$form['cache']['contexts']['#description'] .= ' ' . $this->t('This block is <em>always</em> varied by the following contexts: %required-context-list.', array('%required-context-list' => $required_context_list));
}
// Add plugin-specific settings for this block type. // Add plugin-specific settings for this block type.
$form += $this->blockForm($form, $form_state); $form += $this->blockForm($form, $form_state);
...@@ -259,10 +228,6 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form ...@@ -259,10 +228,6 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
// Remove the admin_label form item element value so it will not persist. // Remove the admin_label form item element value so it will not persist.
$form_state->unsetValue('admin_label'); $form_state->unsetValue('admin_label');
// Transform the #type = checkboxes value to a numerically indexed array.
$contexts = $form_state->getValue(array('cache', 'contexts'));
$form_state->setValue(array('cache', 'contexts'), array_values(array_filter($contexts)));
$this->blockValidate($form, $form_state); $this->blockValidate($form, $form_state);
} }
...@@ -340,16 +305,6 @@ public function setTransliteration(TransliterationInterface $transliteration) { ...@@ -340,16 +305,6 @@ public function setTransliteration(TransliterationInterface $transliteration) {
$this->transliteration = $transliteration; $this->transliteration = $transliteration;
} }
/**
* Returns the cache contexts required for this block.
*
* @return array
* The required cache contexts IDs.
*/
protected function getRequiredCacheContexts() {
return array();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -361,9 +316,7 @@ public function getCacheKeys() { ...@@ -361,9 +316,7 @@ public function getCacheKeys() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getCacheContexts() { public function getCacheContexts() {
// Return the required cache contexts, merged with the user-configured cache return [];
// contexts, if any.
return array_merge($this->getRequiredCacheContexts(), $this->configuration['cache']['contexts']);
} }
/** /**
......
...@@ -96,13 +96,6 @@ public function defaultConfiguration() { ...@@ -96,13 +96,6 @@ public function defaultConfiguration() {
return array( return array(
'block_count' => 10, 'block_count' => 10,
'feed' => NULL, 'feed' => NULL,
// Modify the default max age for the 'Aggregator Feed' blocks:
// modifications made to feeds or feed items will automatically invalidate
// corresponding cache tags, therefore allowing us to cache these blocks
// forever.
'cache' => array(
'max_age' => \Drupal\Core\Cache\Cache::PERMANENT,
),
); );
} }
......
...@@ -75,10 +75,7 @@ protected function setUp() { ...@@ -75,10 +75,7 @@ protected function setUp() {
* Test "user.roles" cache context. * Test "user.roles" cache context.
*/ */
function testCachePerRole() { function testCachePerRole() {
$this->setBlockCacheConfig(array( \Drupal::state()->set('block_test.cache_contexts', ['user.roles']);
'max_age' => 600,
'contexts' => array('user.roles'),
));
// Enable our test block. Set some content for it to display. // Enable our test block. Set some content for it to display.
$current_content = $this->randomMachineName(); $current_content = $this->randomMachineName();
...@@ -125,9 +122,7 @@ function testCachePerRole() { ...@@ -125,9 +122,7 @@ function testCachePerRole() {
* Test a cacheable block without any cache context. * Test a cacheable block without any cache context.
*/ */
function testCacheGlobal() { function testCacheGlobal() {
$this->setBlockCacheConfig(array( \Drupal::state()->set('block_test.cache_contexts', []);
'max_age' => 600,
));
$current_content = $this->randomMachineName(); $current_content = $this->randomMachineName();
\Drupal::state()->set('block_test.content', $current_content); \Drupal::state()->set('block_test.content', $current_content);
...@@ -170,10 +165,7 @@ function testNoCache() { ...@@ -170,10 +165,7 @@ function testNoCache() {
* Test "user" cache context. * Test "user" cache context.
*/ */
function testCachePerUser() { function testCachePerUser() {
$this->setBlockCacheConfig(array( \Drupal::state()->set('block_test.cache_contexts', ['user']);
'max_age' => 600,
'contexts' => array('user'),
));
$current_content = $this->randomMachineName(); $current_content = $this->randomMachineName();
\Drupal::state()->set('block_test.content', $current_content); \Drupal::state()->set('block_test.content', $current_content);
...@@ -202,10 +194,7 @@ function testCachePerUser() { ...@@ -202,10 +194,7 @@ function testCachePerUser() {
* Test "url" cache context. * Test "url" cache context.
*/ */
function testCachePerPage() { function testCachePerPage() {
$this->setBlockCacheConfig(array( \Drupal::state()->set('block_test.cache_contexts', ['url']);
'max_age' => 600,
'contexts' => array('url'),
));
$current_content = $this->randomMachineName(); $current_content = $this->randomMachineName();
\Drupal::state()->set('block_test.content', $current_content); \Drupal::state()->set('block_test.content', $current_content);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\block\Tests; namespace Drupal\block\Tests;
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormState;
use Drupal\simpletest\KernelTestBase; use Drupal\simpletest\KernelTestBase;
use Drupal\block\BlockInterface; use Drupal\block\BlockInterface;
...@@ -45,8 +46,7 @@ public function testBlockInterface() { ...@@ -45,8 +46,7 @@ public function testBlockInterface() {
'provider' => 'block_test', 'provider' => 'block_test',
'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
'cache' => array( 'cache' => array(
'max_age' => 0, 'max_age' => Cache::PERMANENT,
'contexts' => array(),
), ),
'display_message' => 'no message set', 'display_message' => 'no message set',
); );
...@@ -65,9 +65,6 @@ public function testBlockInterface() { ...@@ -65,9 +65,6 @@ public function testBlockInterface() {
$period = array_map(array(\Drupal::service('date.formatter'), 'formatInterval'), array_combine($period, $period)); $period = array_map(array(\Drupal::service('date.formatter'), 'formatInterval'), array_combine($period, $period));
$period[0] = '<' . t('no caching') . '>'; $period[0] = '<' . t('no caching') . '>';
$period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever'); $period[\Drupal\Core\Cache\Cache::PERMANENT] = t('Forever');
$contexts = \Drupal::service("cache_contexts")->getLabels();
unset($contexts['theme']);
unset($contexts['languages']);
$expected_form = array( $expected_form = array(
'provider' => array( 'provider' => array(
'#type' => 'value', '#type' => 'value',
...@@ -98,21 +95,9 @@ public function testBlockInterface() { ...@@ -98,21 +95,9 @@ public function testBlockInterface() {
'#type' => 'select', '#type' => 'select',
'#title' => t('Maximum age'), '#title' => t('Maximum age'),
'#description' => t('The maximum time this block may be cached.'), '#description' => t('The maximum time this block may be cached.'),
'#default_value' => 0, '#default_value' => Cache::PERMANENT,
'#options' => $period, '#options' => $period,
), ),
'contexts' => array(
'#type' => 'checkboxes',
'#title' => t('Vary by context'),
'#description' => t('The contexts this cached block must be varied by. <em>All</em> blocks are varied by language and theme.'),
'#default_value' => array(),
'#options' => $contexts,
'#states' => array(
'disabled' => array(
':input[name="settings[cache][max_age]"]' => array('value' => (string) 0),
),
),
),
), ),
'display_message' => array( 'display_message' => array(
'#type' => 'textfield', '#type' => 'textfield',
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\block\Tests; namespace Drupal\block\Tests;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\Entity\ConfigEntityStorage; use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\simpletest\KernelTestBase; use Drupal\simpletest\KernelTestBase;
use Drupal\block_test\Plugin\Block\TestHtmlBlock; use Drupal\block_test\Plugin\Block\TestHtmlBlock;
...@@ -99,8 +100,7 @@ protected function createTests() { ...@@ -99,8 +100,7 @@ protected function createTests() {
'provider' => 'block_test', 'provider' => 'block_test',
'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE, 'label_display' => BlockInterface::BLOCK_LABEL_VISIBLE,
'cache' => array( 'cache' => array(
'max_age' => 0, 'max_age' => Cache::PERMANENT,
'contexts' => array(),
), ),
), ),
'visibility' => array(), 'visibility' => array(),
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
namespace Drupal\block\Tests; namespace Drupal\block\Tests;
use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\simpletest\WebTestBase; use Drupal\simpletest\WebTestBase;
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\block\Entity\Block; use Drupal\block\Entity\Block;
...@@ -320,7 +319,7 @@ public function testBlockCacheTags() { ...@@ -320,7 +319,7 @@ public function testBlockCacheTags() {
$config->save(); $config->save();
// Place the "Powered by Drupal" block. // Place the "Powered by Drupal" block.
$block = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered', 'cache' => array('max_age' => 315360000))); $block = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered'));
// Prime the page cache. // Prime the page cache.
$this->drupalGet('<front>'); $this->drupalGet('<front>');
...@@ -361,7 +360,7 @@ public function testBlockCacheTags() { ...@@ -361,7 +360,7 @@ public function testBlockCacheTags() {
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
// Place the "Powered by Drupal" block another time; verify a cache miss. // Place the "Powered by Drupal" block another time; verify a cache miss.
$block_2 = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered-2', 'cache' => array('max_age' => 315360000))); $block_2 = $this->drupalPlaceBlock('system_powered_by_block', array('id' => 'powered-2'));
$this->drupalGet('<front>'); $this->drupalGet('<front>');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
......
...@@ -149,15 +149,6 @@ protected function verifyRenderCacheHandling() { ...@@ -149,15 +149,6 @@ protected function verifyRenderCacheHandling() {
$request_method = $request->server->get('REQUEST_METHOD'); $request_method = $request->server->get('REQUEST_METHOD');
$request->setMethod('GET'); $request->setMethod('GET');
// Test that entities with caching disabled do not generate a cache entry.
$build = $this->getBlockRenderArray();
$this->assertTrue(isset($build['#cache']) && array_keys($build['#cache']) == array('contexts', 'tags', 'max-age'), 'The render array element of uncacheable blocks is not cached, but does have cache contexts, tags & max-age set.');
// Enable block caching.
$this->setBlockCacheConfig(array(
'max_age' => 600,
));
// Test that a cache entry is created. // Test that a cache entry is created.
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$cid = 'entity_view:block:test_block:en:core'; $cid = 'entity_view:block:test_block:en:core';
...@@ -194,19 +185,10 @@ public function testBlockViewBuilderAlter() { ...@@ -194,19 +185,10 @@ public function testBlockViewBuilderAlter() {
// Enable the block view alter hook that adds a suffix, for basic testing. // Enable the block view alter hook that adds a suffix, for basic testing.
\Drupal::state()->set('block_test_view_alter_suffix', TRUE); \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
Cache::invalidateTags($this->block->getCacheTags());
// Basic: non-empty block.
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.'); $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
$this->assertIdentical(drupal_render($build), 'Llamas &gt; unicorns!<br>Goodbye!'); $this->assertIdentical(drupal_render($build), 'Llamas &gt; unicorns!<br>Goodbye!');
// Basic: empty block.
\Drupal::state()->set('block_test.content', NULL);
$build = $this->getBlockRenderArray();
$this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block without content is altered.');
$this->assertIdentical(drupal_render($build), '<br>Goodbye!');
// Disable the block view alter hook that adds a suffix, for basic testing.
\Drupal::state()->set('block_test_view_alter_suffix', FALSE); \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
// Force a request via GET so we can get drupal_render() cache working. // Force a request via GET so we can get drupal_render() cache working.
...@@ -214,13 +196,13 @@ public function testBlockViewBuilderAlter() { ...@@ -214,13 +196,13 @@ public function testBlockViewBuilderAlter() {
$request_method = $request->server->get('REQUEST_METHOD'); $request_method = $request->server->get('REQUEST_METHOD');
$request->setMethod('GET'); $request->setMethod('GET');
\Drupal::state()->set('block_test.content', NULL);
Cache::invalidateTags($this->block->getCacheTags());
$default_keys = array('entity_view', 'block', 'test_block'); $default_keys = array('entity_view', 'block', 'test_block');
$default_tags = array('block_view', 'config:block.block.test_block'); $default_tags = array('block_view', 'config:block.block.test_block');
// Advanced: cached block, but an alter hook adds an additional cache key. // Advanced: cached block, but an alter hook adds an additional cache key.
$this->setBlockCacheConfig(array(
'max_age' => 600,
));
$alter_add_key = $this->randomMachineName(); $alter_add_key = $this->randomMachineName();
\Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key); \Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key);
$cid = 'entity_view:block:test_block:' . $alter_add_key . ':en:core'; $cid = 'entity_view:block:test_block:' . $alter_add_key . ':en:core';
...@@ -262,75 +244,6 @@ public function testBlockViewBuilderAlter() { ...@@ -262,75 +244,6 @@ public function testBlockViewBuilderAlter() {
$request->setMethod($request_method); $request->setMethod($request_method);
} }
/**
* Tests block render cache handling with configurable cache contexts.
*
* This is only intended to test that an existing block can be configured with
* additional contexts, not to test that each context works correctly.
*
* @see \Drupal\block\Tests\BlockCacheTest
*/
public function testBlockViewBuilderCacheContexts() {
$cache_contexts = \Drupal::service("cache_contexts");
// Force a request via GET so we can get drupal_render() cache working.
$request = \Drupal::request();
$request_method = $request->server->get('REQUEST_METHOD');
$request->setMethod('GET');
// First: no cache context.
$this->setBlockCacheConfig(array(
'max_age' => 600,
));
$build = $this->getBlockRenderArray();
$cid = implode(':', $build['#cache']['keys']);
drupal_render($build);
$this->assertTrue($this->container->get('cache.render', $cid), 'The block render element has been cached.');
// Second: the "per URL" cache context.
$this->setBlockCacheConfig(array(
'max_age' => 600,
'contexts' => array('url'),
));
$old_cid = $cid;
$build = $this->getBlockRenderArray();
$cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts']));
$cid = implode(':', $cid_parts);
drupal_render($build);
$this->assertTrue($this->container->get('cache.render', $cid), 'The block render element has been cached.');
$this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.');
// Third: the same block configuration, but a different URL.
$original_url_cache_context = $this->container->get('cache_context.url');
$request_stack = new RequestStack();
$request_stack->push(Request::create('/foo'));
$temp_context = new UrlCacheContext($request_stack);
$this->container->set('cache_context.url', $temp_context);
$old_cid = $cid;
$build = $this->getBlockRenderArray();
$cid_parts = array_merge($build['#cache']['keys'], $cache_contexts->convertTokensToKeys($build['#cache']['contexts']));
$cid = implode(':', $cid_parts);
drupal_render($build);
$this->assertTrue($this->container->get('cache.render', $cid), 'The block render element has been cached.');
$this->assertNotEqual($cid, $old_cid, 'The cache ID has changed.');
$this->container->set('cache_context.url', $original_url_cache_context);
// Restore the previous request method.
$request->setMethod($request_method);
}
/**
* Sets the test block's cache configuration.
*
* @param array $cache_config
* The desired cache configuration.
*/
protected function setBlockCacheConfig(array $cache_config) {
$block = $this->block->getPlugin();
$block->setConfigurationValue('cache', $cache_config);
$this->block->save();
}
/** /**
* Get a fully built render array for a block. * Get a fully built render array for a block.
* *
......
...@@ -273,7 +273,7 @@ public function testBlockRendering() { ...@@ -273,7 +273,7 @@ public function testBlockRendering() {
public function testBlockContextualLinks() { public function testBlockContextualLinks() {
$this->drupalLogin($this->drupalCreateUser(array('administer views', 'access contextual links', 'administer blocks'))); $this->drupalLogin($this->drupalCreateUser(array('administer views', 'access contextual links', 'administer blocks')));
$block = $this->drupalPlaceBlock('views_block:test_view_block-block_1'); $block = $this->drupalPlaceBlock('views_block:test_view_block-block_1');
$cached_block = $this->drupalPlaceBlock('views_block:test_view_block-block_1', array('cache' => array('max_age' => 3600))); $cached_block = $this->drupalPlaceBlock('views_block:test_view_block-block_1');
$this->drupalGet('test-page'); $this->drupalGet('test-page');
$id = 'block:block=' . $block->id() . ':|entity.view.edit_form:view=test_view_block:location=block&name=test_view_block&display_id=block_1'; $id = 'block:block=' . $block->id() . ':|entity.view.edit_form:view=test_view_block:location=block&name=test_view_block&display_id=block_1';
......
...@@ -32,4 +32,11 @@ public function build() { ...@@ -32,4 +32,11 @@ public function build() {
return $build; return $build;
} }
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return \Drupal::state()->get('block_test.cache_contexts', []);
}
} }
...@@ -98,12 +98,6 @@ public function defaultConfiguration() { ...@@ -98,12 +98,6 @@ public function defaultConfiguration() {
'status' => TRUE, 'status' => TRUE,
'info' => '', 'info' => '',
'view_mode' => 'full', 'view_mode' => 'full',
// Modify the default max age for custom block blocks: modifications made
// to them will automatically invalidate corresponding cache tags, thus
// allowing us to cache custom block blocks forever.
'cache' => array(
'max_age' => \Drupal\Core\Cache\Cache::PERMANENT,
),
); );
} }
......
...@@ -64,7 +64,7 @@ protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) { ...@@ -64,7 +64,7 @@ protected function getAdditionalCacheTagsForEntity(EntityInterface $entity) {
* Tests that the block is cached with the correct contexts and tags. * Tests that the block is cached with the correct contexts and tags.
*/ */
public function testBlock() { public function testBlock() {
$block = $this->drupalPlaceBlock('block_content:' . $this->entity->uuid(), ['cache' => []]); $block = $this->drupalPlaceBlock('block_content:' . $this->entity->uuid());
$build = $this->container->get('entity.manager')->getViewBuilder('block')->view($block, 'block'); $build = $this->container->get('entity.manager')->getViewBuilder('block')->view($block, 'block');
// Render the block. // Render the block.
......
...@@ -16,9 +16,6 @@ settings: ...@@ -16,9 +16,6 @@ settings:
label: 'Foobar Gorilla' label: 'Foobar Gorilla'
provider: block_content provider: block_content