Commit 2ca54697 authored by catch's avatar catch

Issue #2215719 by Wim Leers: Cache tags set by #pre_render callbacks are lost in page cache.

parent 2cfe1894
...@@ -3990,6 +3990,12 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) { ...@@ -3990,6 +3990,12 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
$suffix = isset($elements['#suffix']) ? $elements['#suffix'] : ''; $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
$elements['#markup'] = $prefix . $elements['#children'] . $suffix; $elements['#markup'] = $prefix . $elements['#children'] . $suffix;
// Collect all cache tags. This allows the caller of drupal_render() to also
// access the complete list of cache tags.
if (!$is_recursive_call || isset($elements['#cache'])) {
$elements['#cache']['tags'] = drupal_render_collect_cache_tags($elements);
}
// Cache the processed element if #cache is set. // Cache the processed element if #cache is set.
if (isset($elements['#cache'])) { if (isset($elements['#cache'])) {
drupal_render_cache_set($elements['#markup'], $elements); drupal_render_cache_set($elements['#markup'], $elements);
...@@ -4196,10 +4202,14 @@ function drupal_render_cache_set(&$markup, array $elements) { ...@@ -4196,10 +4202,14 @@ function drupal_render_cache_set(&$markup, array $elements) {
$data['#post_render_cache'] = $elements['#post_render_cache']; $data['#post_render_cache'] = $elements['#post_render_cache'];
} }
// Persist cache tags associated with this element.
if (isset($elements['#cache']['tags'])) {
$data['#cache']['tags'] = $elements['#cache']['tags'];
}
$bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache'; $bin = isset($elements['#cache']['bin']) ? $elements['#cache']['bin'] : 'cache';
$expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : Cache::PERMANENT; $expire = isset($elements['#cache']['expire']) ? $elements['#cache']['expire'] : Cache::PERMANENT;
$tags = drupal_render_collect_cache_tags($elements); \Drupal::cache($bin)->set($cid, $data, $expire, $elements['#cache']['tags']);
\Drupal::cache($bin)->set($cid, $data, $expire, $tags);
} }
/** /**
......
...@@ -1967,14 +1967,6 @@ function template_preprocess_html(&$variables) { ...@@ -1967,14 +1967,6 @@ function template_preprocess_html(&$variables) {
} }
} }
// Initializes attributes which are specific to the html and body elements.
$variables['html_attributes'] = new Attribute;
// HTML element attributes.
$language_interface = \Drupal::service('language_manager')->getCurrentLanguage();
$variables['html_attributes']['lang'] = $language_interface->id;
$variables['html_attributes']['dir'] = $language_interface->direction ? 'rtl' : 'ltr';
$site_config = \Drupal::config('system.site'); $site_config = \Drupal::config('system.site');
// Construct page title. // Construct page title.
if ($page->hasTitle()) { if ($page->hasTitle()) {
......
...@@ -71,9 +71,9 @@ protected function createHtmlFragment($page_content, Request $request) { ...@@ -71,9 +71,9 @@ protected function createHtmlFragment($page_content, Request $request) {
); );
} }
$cache_tags = $this->drupalRenderCollectCacheTags($page_content); $content = $this->drupalRender($page_content);
$cache = !empty($cache_tags) ? array('tags' => $cache_tags) : array(); $cache = !empty($page_content['#cache']['tags']) ? array('tags' => $page_content['#cache']['tags']) : array();
$fragment = new HtmlFragment($this->drupalRender($page_content), $cache); $fragment = new HtmlFragment($content, $cache);
// A title defined in the return always wins. // A title defined in the return always wins.
if (isset($page_content['#title'])) { if (isset($page_content['#title'])) {
...@@ -95,13 +95,4 @@ protected function drupalRender(&$elements, $is_recursive_call = FALSE) { ...@@ -95,13 +95,4 @@ protected function drupalRender(&$elements, $is_recursive_call = FALSE) {
return drupal_render($elements, $is_recursive_call); return drupal_render($elements, $is_recursive_call);
} }
/**
* Wraps drupal_render_collect_cache_tags()
*
* @todo: Remove as part of https://drupal.org/node/2182149
*/
protected function drupalRenderCollectCacheTags($element, $tags = array()) {
return drupal_render_collect_cache_tags($element, $tags);
}
} }
...@@ -48,15 +48,14 @@ public function render(HtmlFragment $fragment, $status_code = 200) { ...@@ -48,15 +48,14 @@ public function render(HtmlFragment $fragment, $status_code = 200) {
// hook_page_build(). This adds the other regions to the page. // hook_page_build(). This adds the other regions to the page.
$page_array = drupal_prepare_page($page_content); $page_array = drupal_prepare_page($page_content);
// Collect cache tags for all the content in all the regions on the page.
$tags = drupal_render_collect_cache_tags($page_array);
// Build the HtmlPage object. // Build the HtmlPage object.
$page = new HtmlPage('', array('tags' => $tags), $fragment->getTitle()); $page = new HtmlPage('', array(), $fragment->getTitle());
$page = $this->preparePage($page, $page_array); $page = $this->preparePage($page, $page_array);
$page->setBodyTop(drupal_render($page_array['page_top'])); $page->setBodyTop(drupal_render($page_array['page_top']));
$page->setBodyBottom(drupal_render($page_array['page_bottom'])); $page->setBodyBottom(drupal_render($page_array['page_bottom']));
$page->setContent(drupal_render($page_array)); $page->setContent(drupal_render($page_array));
// Collect cache tags for all the content in all the regions on the page.
$page->setCacheTags($page_array['#cache']['tags']);
$page->setStatusCode($status_code); $page->setStatusCode($status_code);
return $page; return $page;
......
...@@ -158,5 +158,15 @@ public function getStatusCode() { ...@@ -158,5 +158,15 @@ public function getStatusCode() {
return $this->statusCode; return $this->statusCode;
} }
/**
* Sets the cache tags associated with this HTML page.
*
* @param array $cache_tags
* The cache tags associated with this HTML page.
*/
public function setCacheTags(array $cache_tags) {
$this->cache['tags'] = $cache_tags;
}
} }
...@@ -65,7 +65,7 @@ function testPageCacheTags() { ...@@ -65,7 +65,7 @@ function testPageCacheTags() {
$cid_parts = array(url($path, array('absolute' => TRUE)), 'html'); $cid_parts = array(url($path, array('absolute' => TRUE)), 'html');
$cid = sha1(implode(':', $cid_parts)); $cid = sha1(implode(':', $cid_parts));
$cache_entry = \Drupal::cache('page')->get($cid); $cache_entry = \Drupal::cache('page')->get($cid);
$this->assertIdentical($cache_entry->tags, array('content:1', 'system_test_cache_tags_page:1')); $this->assertIdentical($cache_entry->tags, array('content:1', 'system_test_cache_tags_page:1', 'pre_render:1'));
Cache::invalidateTags($tags); Cache::invalidateTags($tags);
$this->drupalGet($path); $this->drupalGet($path);
......
...@@ -500,6 +500,7 @@ function testDrupalRenderPostRenderCache() { ...@@ -500,6 +500,7 @@ function testDrupalRenderPostRenderCache() {
'#markup' => '<p>#cache enabled, GET</p>', '#markup' => '<p>#cache enabled, GET</p>',
'#attached' => $test_element['#attached'], '#attached' => $test_element['#attached'],
'#post_render_cache' => $test_element['#post_render_cache'], '#post_render_cache' => $test_element['#post_render_cache'],
'#cache' => array('tags' => array()),
); );
$this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
...@@ -619,6 +620,7 @@ function testDrupalRenderChildrenPostRenderCache() { ...@@ -619,6 +620,7 @@ function testDrupalRenderChildrenPostRenderCache() {
$context_3, $context_3,
) )
), ),
'#cache' => array('tags' => array()),
); );
$dom = Html::load($cached_element['#markup']); $dom = Html::load($cached_element['#markup']);
...@@ -702,6 +704,7 @@ function testDrupalRenderChildrenPostRenderCache() { ...@@ -702,6 +704,7 @@ function testDrupalRenderChildrenPostRenderCache() {
$context_3, $context_3,
) )
), ),
'#cache' => array('tags' => array()),
); );
$dom = Html::load($cached_parent_element['#markup']); $dom = Html::load($cached_parent_element['#markup']);
...@@ -727,6 +730,7 @@ function testDrupalRenderChildrenPostRenderCache() { ...@@ -727,6 +730,7 @@ function testDrupalRenderChildrenPostRenderCache() {
$context_3, $context_3,
) )
), ),
'#cache' => array('tags' => array()),
); );
$dom = Html::load($cached_child_element['#markup']); $dom = Html::load($cached_child_element['#markup']);
...@@ -830,6 +834,7 @@ function testDrupalRenderRenderCachePlaceholder() { ...@@ -830,6 +834,7 @@ function testDrupalRenderRenderCachePlaceholder() {
$expected_token => $context, $expected_token => $context,
), ),
), ),
'#cache' => array('tags' => array()),
); );
$this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
...@@ -920,6 +925,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { ...@@ -920,6 +925,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
$expected_token => $context, $expected_token => $context,
), ),
), ),
'#cache' => array('tags' => array()),
); );
$this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the child element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the child element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
...@@ -944,6 +950,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { ...@@ -944,6 +950,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
$expected_token => $context, $expected_token => $context,
), ),
), ),
'#cache' => array('tags' => array()),
); );
$this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the parent element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the parent element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
...@@ -972,6 +979,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { ...@@ -972,6 +979,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
$expected_token => $context, $expected_token => $context,
), ),
), ),
'#cache' => array('tags' => array()),
); );
$this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the child element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the child element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
......
...@@ -27,7 +27,6 @@ public function getFormId() { ...@@ -27,7 +27,6 @@ public function getFormId() {
public function buildForm(array $form, array &$form_state) { public function buildForm(array $form, array &$form_state) {
$form['#action'] = url('ajax-test/dialog'); $form['#action'] = url('ajax-test/dialog');
$form['#cache'] = TRUE;
$form['description'] = array( $form['description'] = array(
'#markup' => '<p>' . t("Ajax Form contents description.") . '</p>', '#markup' => '<p>' . t("Ajax Form contents description.") . '</p>',
......
...@@ -41,14 +41,27 @@ public function lockExit() { ...@@ -41,14 +41,27 @@ public function lockExit() {
/** /**
* Set cache tag on on the returned render array. * Set cache tag on on the returned render array.
*/ */
function system_test_cache_tags_page() { public function system_test_cache_tags_page() {
$build['main'] = array( $build['main'] = array(
'#markup' => 'Cache tags page example',
'#cache' => array('tags' => array('system_test_cache_tags_page' => TRUE)), '#cache' => array('tags' => array('system_test_cache_tags_page' => TRUE)),
'#pre_render' => array(
'\Drupal\system_test\Controller\SystemTestController::preRenderCacheTags',
),
'message' => array(
'#markup' => 'Cache tags page example',
),
); );
return $build; return $build;
} }
/**
* Sets a cache tag on an element to help test #pre_render and cache tags.
*/
public static function preRenderCacheTags($elements) {
$elements['#cache']['tags']['pre_render'] = TRUE;
return $elements;
}
/** /**
* @todo Remove system_test_authorize_init_page(). * @todo Remove system_test_authorize_init_page().
*/ */
......
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