Commit 407f1d11 authored by alexpott's avatar alexpott

Issue #2185617 by Wim Leers, voidberg, drifter: Each page cache entry should...

Issue #2185617 by Wim Leers, voidberg, drifter: Each page cache entry should have a theme cache tag.
parent f130cc3e
......@@ -1925,6 +1925,22 @@ function drupal_pre_render_html(array $element) {
return $element;
}
/**
* #pre_render callback for the page element type.
*
* @param array $element
* A structured array containing the page element type build properties.
*
* @see system_element_info()
*/
function drupal_pre_render_page(array $element) {
global $theme;
$element['#cache']['tags']['theme'] = $theme;
$element['#cache']['tags']['theme_global_settings'] = TRUE;
return $element;
}
/**
* Prepares variables for HTML document templates.
*
......
......@@ -43,9 +43,9 @@ public static function getLabel() {
*/
public function getContext() {
$context_parts = array();
if ($this->language_manager->isMultilingual()) {
foreach ($this->language_manager->getLanguageTypes() as $type) {
$context_parts[] = $this->language_manager->getCurrentLanguage($type)->id;
if ($this->languageManager->isMultilingual()) {
foreach ($this->languageManager->getLanguageTypes() as $type) {
$context_parts[] = $this->languageManager->getCurrentLanguage($type)->id;
}
}
return implode(':', $context_parts);
......
......@@ -74,6 +74,7 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
'content' => TRUE,
'block_view' => TRUE,
'block' => array($entity->id()),
'theme' => $entity->get('theme'),
);
$build[$entity_id]['#cache']['tags'] = NestedArray::mergeDeep($default_cache_tags, $plugin->getCacheTags());
......
......@@ -160,8 +160,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
// When placing a new block, invalidate all cache entries for this theme,
// since any page that uses this theme might be affected.
else {
// @todo Replace with theme cache tag: https://drupal.org/node/2185617
Cache::invalidateTags(array('content' => TRUE));
Cache::invalidateTags(array('theme' => $this->theme));
}
}
......
......@@ -281,6 +281,8 @@ public function testBlockCacheTags() {
$cid = sha1(implode(':', $cid_parts));
$cache_entry = \Drupal::cache('render')->get($cid);
$expected_cache_tags = array(
'theme:stark',
'theme_global_settings:1',
'content:1',
'block_view:1',
'block:powered',
......@@ -288,6 +290,13 @@ public function testBlockCacheTags() {
);
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:stark');
$expected_cache_tags = array(
'content:1',
'block_view:1',
'block:powered',
'theme:stark',
'block_plugin:system_powered_by_block',
);
$this->assertIdentical($cache_entry->tags, $expected_cache_tags);
// The "Powered by Drupal" block is modified; verify a cache miss.
......@@ -312,6 +321,8 @@ public function testBlockCacheTags() {
$cid = sha1(implode(':', $cid_parts));
$cache_entry = \Drupal::cache('render')->get($cid);
$expected_cache_tags = array(
'theme:stark',
'theme_global_settings:1',
'content:1',
'block_view:1',
'block:powered-2',
......@@ -323,6 +334,7 @@ public function testBlockCacheTags() {
'content:1',
'block_view:1',
'block:powered',
'theme:stark',
'block_plugin:system_powered_by_block',
);
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered:en:stark');
......@@ -331,6 +343,7 @@ public function testBlockCacheTags() {
'content:1',
'block_view:1',
'block:powered-2',
'theme:stark',
'block_plugin:system_powered_by_block',
);
$cache_entry = \Drupal::cache('render')->get('entity_view:block:powered-2:en:stark');
......
......@@ -221,7 +221,7 @@ public function testBlockViewBuilderAlter() {
$this->container->get('request')->setMethod('GET');
$default_keys = array('entity_view', 'block', 'test_block', 'en', 'cache_context.theme');
$default_tags = array('content' => TRUE, 'block_view' => TRUE, 'block' => array('test_block'), 'block_plugin' => array('test_cache'));
$default_tags = array('content' => TRUE, 'block_view' => TRUE, 'block' => array('test_block'), 'theme' => 'stark', 'block_plugin' => array('test_cache'));
// Advanced: cached block, but an alter hook adds an additional cache key.
$this->setBlockCacheConfig(array(
......@@ -236,7 +236,7 @@ public function testBlockViewBuilderAlter() {
$this->assertIdentical(drupal_render($build), '');
$cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'block_plugin:test_cache');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache');
$this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid);
......@@ -250,7 +250,7 @@ public function testBlockViewBuilderAlter() {
$this->assertIdentical(drupal_render($build), '');
$cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'block_plugin:test_cache', $alter_add_tag . ':1');
$expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache', $alter_add_tag . ':1');
$this->assertIdentical($cache_entry->tags, array_combine($expected_flattened_tags, $expected_flattened_tags)); //, 'The block render element has been cached with the expected cache tags.');
$this->container->get('cache.render')->delete($cid);
......
......@@ -59,6 +59,8 @@ public function testMenuBlock() {
// Verify a cache hit, but also the presence of the correct cache tags.
$expected_tags = array(
'theme:stark',
'theme_global_settings:1',
'content:1',
'block_view:1',
'block:' . $block->id(),
......@@ -117,7 +119,7 @@ public function testMenuBlock() {
$this->verifyPageCache($path, 'MISS');
// Verify a cache hit.
$this->verifyPageCache($path, 'HIT', array('content:1'));
$this->verifyPageCache($path, 'HIT', array('content:1', 'theme:stark', 'theme_global_settings:1'));
}
}
......@@ -419,6 +419,16 @@ public function submitForm(array &$form, array &$form_state) {
theme_settings_convert_to_config($values, $config)->save();
// Invalidate either the theme-specific cache tag or the global theme
// settings cache tag, depending on whose settings were actually changed.
if (isset($values['theme'])) {
Cache::invalidateTags(array('theme' => $values['theme']));
}
else {
Cache::invalidateTags(array('theme_global_settings' => TRUE));
}
// @todo Remove this in https://drupal.org/node/2124957.
Cache::invalidateTags(array('content' => TRUE));
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\system\Plugin\Block;
use Drupal\Component\Utility\NestedArray;
use Drupal\block\BlockBase;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
......@@ -44,7 +45,7 @@ class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInt
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $current_user;
protected $currentUser;
/**
* Creates a SystemBrandingBlock instance.
......@@ -92,6 +93,12 @@ public function defaultConfiguration() {
'use_site_name' => TRUE,
'use_site_slogan' => TRUE,
'label_display' => FALSE,
// Modify the default max age for the 'Site branding' block: the site
// logo, name and slogan are static for a given language, except when the
// theme settings are updated (global theme settings or theme-specific
// settings). Cache tags for those cases ensure that a cached version of
// this block is invalidated automatically.
'cache' => array('max_age' => \Drupal\Core\Cache\Cache::PERMANENT),
);
}
......@@ -108,12 +115,12 @@ public function blockForm($form, &$form_state) {
if ($administer_themes_access) {
// Get paths to theme settings pages.
$appearance_url = $this->urlGenerator->generateFromRoute('system.themes_page');
$appearance_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings');
$theme_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings_theme', array('theme' => $theme));
// Provide links to the Appearance and Theme Settings pages
// Provide links to the Appearance Settings and Theme Settings pages
// if the user has access to administer themes.
$site_logo_description = $this->t('Defined on the <a href="@appearance">Appearance</a> or <a href="@theme">Theme Settings</a> page.', array('@appearance' => $appearance_url, '@theme' => $theme_settings_url));
$site_logo_description = $this->t('Defined on the <a href="@appearance">Appearance Settings</a> or <a href="@theme">Theme Settings</a> page.', array('@appearance' => $appearance_settings_url, '@theme' => $theme_settings_url));
}
else {
// Explain that the user does not have access to the Appearance and Theme
......@@ -200,4 +207,29 @@ public function build() {
return $build;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
// The theme-specific cache tag is set automatically for each block, but the
// output of this block also depends on the global theme settings.
$tags = array(
'theme_global_setting' => TRUE,
);
return NestedArray::mergeDeep(parent::getCacheTags(), $tags);
}
/**
* {@inheritdoc}
*/
protected function getRequiredCacheContexts() {
// The 'Site branding' block must be cached per theme and per language: the
// site logo, name and slogan are defined on a per-theme basis, and the name
// and slogan may be translated.
// We don't need to return 'cache_context.theme' also, because that cache
// context is automatically applied to all blocks.
// @see \Drupal\block\BlockViewBuilder::viewMultiple()
return array('cache_context.language');
}
}
......@@ -66,7 +66,14 @@ function testPageCacheTags() {
$cid = sha1(implode(':', $cid_parts));
$cache_entry = \Drupal::cache('render')->get($cid);
sort($cache_entry->tags);
$this->assertIdentical($cache_entry->tags, array('content:1', 'pre_render:1', 'system_test_cache_tags_page:1'));
$expected_tags = array(
'content:1',
'pre_render:1',
'system_test_cache_tags_page:1',
'theme:stark',
'theme_global_settings:1',
);
$this->assertIdentical($cache_entry->tags, $expected_tags);
Cache::invalidateTags($tags);
$this->drupalGet($path);
......
......@@ -77,6 +77,8 @@ function testPageCacheTags() {
// Full node page 1.
$this->verifyPageCacheTags('node/' . $node_1->id(), array(
'content:1',
'theme:bartik',
'theme_global_settings:1',
'block_view:1',
'block:bartik_content',
'block:bartik_tools',
......@@ -100,6 +102,8 @@ function testPageCacheTags() {
// Full node page 2.
$this->verifyPageCacheTags('node/' . $node_2->id(), array(
'content:1',
'theme:bartik',
'theme_global_settings:1',
'block_view:1',
'block:bartik_content',
'block:bartik_tools',
......
......@@ -210,6 +210,8 @@ public function testReferencedEntity() {
$non_referencing_entity_path = $this->non_referencing_entity->getSystemPath();
$listing_path = 'entity_test/list/' . $entity_type . '_reference/' . $entity_type . '/' . $this->entity->id();
$theme_cache_tags = array('content:1', 'theme:stark', 'theme_global_settings:1');
// Generate the standardized entity cache tags.
$cache_tag = $entity_type . ':' . $this->entity->id();
$view_cache_tag = $entity_type . '_view:1';
......@@ -232,7 +234,7 @@ public function testReferencedEntity() {
$this->verifyPageCache($referencing_entity_path, 'MISS');
// Verify a cache hit, but also the presence of the correct cache tags.
$tags = array_merge(array('content:1'), $referencing_entity_cache_tags);
$tags = array_merge($theme_cache_tags, $referencing_entity_cache_tags);
$this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
// Also verify the existence of an entity render cache entry.
......@@ -245,7 +247,7 @@ public function testReferencedEntity() {
$this->verifyPageCache($non_referencing_entity_path, 'MISS');
// Verify a cache hit, but also the presence of the correct cache tags.
$tags = array_merge(array('content:1'), $non_referencing_entity_cache_tags);
$tags = array_merge($theme_cache_tags, $non_referencing_entity_cache_tags);
$this->verifyPageCache($non_referencing_entity_path, 'HIT', $tags);
// Also verify the existence of an entity render cache entry.
......@@ -259,7 +261,7 @@ public function testReferencedEntity() {
$this->verifyPageCache($listing_path, 'MISS');
// Verify a cache hit, but also the presence of the correct cache tags.
$tags = array_merge(array('content:1'), $referencing_entity_cache_tags);
$tags = array_merge($theme_cache_tags, $referencing_entity_cache_tags);
$this->verifyPageCache($listing_path, 'HIT', $tags);
......@@ -407,13 +409,12 @@ public function testReferencedEntity() {
$this->verifyPageCache($non_referencing_entity_path, 'HIT');
// Verify cache hits.
$tags = array(
'content:1',
$tags = array_merge($theme_cache_tags, array(
'entity_test_view:1',
'entity_test:' . $this->referencing_entity->id(),
);
));
$this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
$this->verifyPageCache($listing_path, 'HIT', array('content:1'));
$this->verifyPageCache($listing_path, 'HIT', $theme_cache_tags);
}
}
......@@ -290,6 +290,7 @@ function system_element_info() {
);
$types['page'] = array(
'#show_messages' => TRUE,
'#pre_render' => array('drupal_pre_render_page'),
'#theme' => 'page',
'#title' => '',
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment