Commit 08b9bd41 authored by catch's avatar catch

Issue #918808 by moshe weitzman, Damien Tournoud, dww: Standardize block cache...

Issue #918808 by moshe weitzman, Damien Tournoud, dww: Standardize block cache as a drupal_render() #cache.
parent 9763ca90
...@@ -185,3 +185,21 @@ function block_install() { ...@@ -185,3 +185,21 @@ function block_install() {
->condition('name', 'block') ->condition('name', 'block')
->execute(); ->execute();
} }
/**
* @defgroup updates-7.x-to-8.x Updates from 7.x to 8.x
* @{
* Update functions from 7.x to 8.x.
*/
/**
* Block cache is always enabled in 8.x.
*/
function block_update_8000() {
variable_del('block_cache');
}
/**
* @} End of "defgroup updates-7.x-to-8.x"
* The next series of updates should start at 9000.
*/
...@@ -313,7 +313,7 @@ function block_page_build(&$page) { ...@@ -313,7 +313,7 @@ function block_page_build(&$page) {
function block_get_blocks_by_region($region) { function block_get_blocks_by_region($region) {
$build = array(); $build = array();
if ($list = block_list($region)) { if ($list = block_list($region)) {
$build = _block_get_renderable_array($list); $build = _block_get_renderable_region($list);
} }
return $build; return $build;
} }
...@@ -326,12 +326,43 @@ function block_get_blocks_by_region($region) { ...@@ -326,12 +326,43 @@ function block_get_blocks_by_region($region) {
* @return * @return
* A renderable array. * A renderable array.
*/ */
function _block_get_renderable_array($list = array()) { function _block_get_renderable_region($list = array()) {
$weight = 0; $weight = 0;
$build = array(); $build = array();
foreach ($list as $key => $block) { foreach ($list as $key => $block) {
$build[$key] = $block->content; $build[$key] = array(
unset($block->content); '#block' => $block,
'#weight' => ++$weight,
'#theme_wrappers' => array('block'),
);
// Block caching is not compatible with node_access modules. We also
// preserve the submission of forms in blocks, by fetching from cache
// only if the request method is 'GET' (or 'HEAD'). User 1 being out of
// the regular 'roles define permissions' schema, it brings too many
// chances of having unwanted output get in the cache and later be served
// to other users. We therefore exclude user 1 from block caching.
if (
$GLOBALS['user']->uid == 1 ||
count(module_implements('node_grants')) ||
!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) ||
in_array($block->cache, array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM))
) {
// Non-cached blocks get built immediately. Provides more content
// that can be easily manipulated during hook_page_alter().
$build[$key] = _block_get_renderable_block($build[$key]);
}
else {
$build[$key] += array(
'#pre_render' => array('_block_get_renderable_block'),
'#cache' => array(
'keys' => array($block->module, $block->delta),
'granularity' => $block->cache,
'bin' => 'block',
'expire' => CACHE_TEMPORARY,
),
);
}
// Add contextual links for this block; skip the main content block, since // Add contextual links for this block; skip the main content block, since
// contextual links are basically output as tabs/local tasks already. Also // contextual links are basically output as tabs/local tasks already. Also
...@@ -341,12 +372,6 @@ function _block_get_renderable_array($list = array()) { ...@@ -341,12 +372,6 @@ function _block_get_renderable_array($list = array()) {
if ($key != 'system_main' && $key != 'system_help') { if ($key != 'system_main' && $key != 'system_help') {
$build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($block->module, $block->delta)); $build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($block->module, $block->delta));
} }
$build[$key] += array(
'#block' => $block,
'#weight' => ++$weight,
);
$build[$key]['#theme_wrappers'][] ='block';
} }
$build['#sorted'] = TRUE; $build['#sorted'] = TRUE;
return $build; return $build;
...@@ -654,9 +679,6 @@ function block_list($region) { ...@@ -654,9 +679,6 @@ function block_list($region) {
if (!isset($blocks[$region])) { if (!isset($blocks[$region])) {
$blocks[$region] = array(); $blocks[$region] = array();
} }
else {
$blocks[$region] = _block_render_blocks($blocks[$region]);
}
return $blocks[$region]; return $blocks[$region];
} }
...@@ -696,6 +718,7 @@ function _block_load_blocks() { ...@@ -696,6 +718,7 @@ function _block_load_blocks() {
global $theme_key; global $theme_key;
$query = db_select('block', 'b'); $query = db_select('block', 'b');
$query->addField('b', 'title', 'subject');
$result = $query $result = $query
->fields('b') ->fields('b')
->condition('b.theme', $theme_key) ->condition('b.theme', $theme_key)
...@@ -808,96 +831,57 @@ function block_block_list_alter(&$blocks) { ...@@ -808,96 +831,57 @@ function block_block_list_alter(&$blocks) {
} }
/** /**
* Render the content and subject for a set of blocks. * Build the content and subject for a block. For cacheable blocks, this is
* * called during #pre_render.
* @param $region_blocks
* An array of block objects such as returned for one region by _block_load_blocks().
* *
* @param $element
* A renderable array.
* @return * @return
* An array of visible blocks as expected by drupal_render(). * A renderable array.
*/ */
function _block_render_blocks($region_blocks) { function _block_get_renderable_block($element) {
foreach ($region_blocks as $key => $block) { $block = $element['#block'];
// Render the block content if it has not been created already.
if (!isset($block->content)) {
// Erase the block from the static array - we'll put it back if it has
// content.
unset($region_blocks[$key]);
// Try fetching the block from cache. Block caching is not compatible
// with node_access modules. We also preserve the submission of forms in
// blocks, by fetching from cache only if the request method is 'GET'
// (or 'HEAD').
if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache('block')->get($cid))) {
$array = $cache->data;
}
else {
$array = module_invoke($block->module, 'block_view', $block->delta);
// Allow modules to modify the block before it is viewed, via either // Render the block content if it has not been created already.
// hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter(). if (!isset($block->content)) {
drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block); $array = module_invoke($block->module, 'block_view', $block->delta);
if (isset($cid)) { // Allow modules to modify the block before it is viewed, via either
cache('block')->set($cid, $array, CACHE_TEMPORARY); // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
} drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);
}
if (isset($array) && is_array($array)) { if (empty($array)) {
foreach ($array as $k => $v) { // Blocks without content should emit no markup at all.
$block->$k = $v; $element += array(
} '#access' => FALSE,
} '#printed' => TRUE,
if (isset($block->content) && $block->content) { );
// Normalize to the drupal_render() structure. }
if (is_string($block->content)) { elseif (isset($array) && is_array($array)) {
$block->content = array('#markup' => $block->content); foreach ($array as $k => $v) {
} $block->$k = $v;
// Override default block title if a custom display title is present.
if ($block->title) {
// Check plain here to allow module generated titles to keep any
// markup.
$block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
}
if (!isset($block->subject)) {
$block->subject = '';
}
$region_blocks["{$block->module}_{$block->delta}"] = $block;
} }
} }
} }
return $region_blocks;
}
/** if (isset($block->content) && $block->content) {
* Assemble the cache_id to use for a given block. // Normalize to the drupal_render() structure.
* if (is_string($block->content)) {
* The cache_id string reflects the viewing context for the current block $block->content = array('#markup' => $block->content);
* instance, obtained by concatenating the relevant context information }
* (user, page, ...) according to the block's cache settings (BLOCK_CACHE_* // Override default block title if a custom display title is present.
* constants). Two block instances can use the same cached content when if ($block->title) {
* they share the same cache_id. // Check plain here to allow module generated titles to keep any
* // markup.
* Theme and language contexts are automatically differentiated. $block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
* }
* @param $block
* @return // Add the content renderable array to the main element.
* The string used as cache_id for the block. $element['content'] = $block->content;
*/ unset($block->content);
function _block_get_cache_id($block) { $element['#block'] = $block;
global $user;
// User 1 being out of the regular 'roles define permissions' schema,
// it brings too many chances of having unwanted output get in the cache
// and later be served to other users. We therefore exclude user 1 from
// block caching.
if (variable_get('block_cache', FALSE) && !in_array($block->cache, array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM)) && $user->uid != 1) {
// Start with common sub-patterns: block identification, theme, language.
$cid_parts[] = $block->module;
$cid_parts[] = $block->delta;
$cid_parts = array_merge($cid_parts, drupal_render_cid_parts($block->cache));
return implode(':', $cid_parts);
} }
return $element;
} }
/** /**
...@@ -992,21 +976,6 @@ function block_menu_delete($menu) { ...@@ -992,21 +976,6 @@ function block_menu_delete($menu) {
->execute(); ->execute();
} }
/**
* Implements hook_form_FORM_ID_alter().
*/
function block_form_system_performance_settings_alter(&$form, &$form_state) {
$disabled = count(module_implements('node_grants'));
$form['caching']['block_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Cache blocks'),
'#default_value' => variable_get('block_cache', FALSE),
'#disabled' => $disabled,
'#description' => $disabled ? t('Block caching is inactive because you have enabled modules defining content access restrictions.') : NULL,
'#weight' => -1,
);
}
/** /**
* Implements hook_admin_paths(). * Implements hook_admin_paths().
*/ */
......
...@@ -513,9 +513,6 @@ class BlockCacheTestCase extends DrupalWebTestCase { ...@@ -513,9 +513,6 @@ class BlockCacheTestCase extends DrupalWebTestCase {
user_save($this->normal_user_alt, array('roles' => $this->normal_user->roles)); user_save($this->normal_user_alt, array('roles' => $this->normal_user->roles));
$this->normal_user_alt->roles = $this->normal_user->roles; $this->normal_user_alt->roles = $this->normal_user->roles;
// Enable block caching.
variable_set('block_cache', TRUE);
// Enable our test block. // Enable our test block.
$edit['blocks[block_test_test_cache][region]'] = 'sidebar_first'; $edit['blocks[block_test_test_cache][region]'] = 'sidebar_first';
$this->drupalPost('admin/structure/block', $edit, t('Save blocks')); $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
......
<?php <?php
/** /**
* @file * @file
* Tests for comment.module. * Tests for comment.module.
*/ */
...@@ -1589,6 +1589,9 @@ class CommentBlockFunctionalTest extends CommentHelperCase { ...@@ -1589,6 +1589,9 @@ class CommentBlockFunctionalTest extends CommentHelperCase {
// block. // block.
$this->drupalLogout(); $this->drupalLogout();
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access comments')); user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
// drupalCreateNode() does not automatically flush content caches unlike
// posting a node from a node form.
cache_clear_all();
$this->drupalGet(''); $this->drupalGet('');
$this->assertNoText($block['title'], t('Block was not found.')); $this->assertNoText($block['title'], t('Block was not found.'));
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access comments')); user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access comments'));
......
...@@ -187,7 +187,7 @@ function dashboard_page_build(&$page) { ...@@ -187,7 +187,7 @@ function dashboard_page_build(&$page) {
} }
$block->subject = t('@title', array('@title' => $block_info[$block->module][$block->delta]['info'])); $block->subject = t('@title', array('@title' => $block_info[$block->module][$block->delta]['info']));
$block_render = array($block->module . '_' . $block->delta => $block); $block_render = array($block->module . '_' . $block->delta => $block);
$build = _block_get_renderable_array($block_render); $build = _block_get_renderable_region($block_render);
$page['content']['dashboard'][$block->region][] = $build; $page['content']['dashboard'][$block->region][] = $build;
} }
} }
...@@ -526,8 +526,7 @@ function dashboard_show_block_content($module, $delta) { ...@@ -526,8 +526,7 @@ function dashboard_show_block_content($module, $delta) {
->fetchObject(); ->fetchObject();
$block_object->enabled = $block_object->page_match = TRUE; $block_object->enabled = $block_object->page_match = TRUE;
$blocks[$module . "_" . $delta] = $block_object; $blocks[$module . "_" . $delta] = $block_object;
$block_content = _block_render_blocks($blocks); $build = _block_get_renderable_region($blocks);
$build = _block_get_renderable_array($block_content);
$rendered_block = drupal_render($build); $rendered_block = drupal_render($build);
print $rendered_block; print $rendered_block;
drupal_exit(); drupal_exit();
...@@ -674,4 +673,3 @@ function theme_dashboard_disabled_block($variables) { ...@@ -674,4 +673,3 @@ function theme_dashboard_disabled_block($variables) {
} }
return $output; return $output;
} }
...@@ -1855,6 +1855,9 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase { ...@@ -1855,6 +1855,9 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase {
// Post an additional node. // Post an additional node.
$node4 = $this->drupalCreateNode($default_settings); $node4 = $this->drupalCreateNode($default_settings);
// drupalCreateNode() does not automatically flush content caches unlike
// posting a node from a node form.
cache_clear_all();
// Test that all four nodes are shown. // Test that all four nodes are shown.
$this->drupalGet(''); $this->drupalGet('');
......
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