Index: modules/block/block.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v retrieving revision 1.57 diff -u -p -r1.57 block.admin.inc --- modules/block/block.admin.inc 18 Sep 2009 00:12:45 -0000 1.57 +++ modules/block/block.admin.inc 21 Sep 2009 18:25:27 -0000 @@ -15,8 +15,10 @@ function block_admin_display($theme = NU // If non-default theme configuration has been selected, set the custom theme. $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland'); + drupal_theme_initialize(); + // Fetch and sort blocks. - $blocks = _block_rehash(); + $blocks = block_rebuild($custom_theme); usort($blocks, '_block_compare'); return drupal_get_form('block_admin_display_form', $blocks, $theme); Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.378 diff -u -p -r1.378 block.module --- modules/block/block.module 20 Sep 2009 07:32:17 -0000 1.378 +++ modules/block/block.module 21 Sep 2009 18:25:27 -0000 @@ -245,83 +245,111 @@ function block_get_blocks_by_region($reg /** * Update the 'block' DB table with the blocks currently exported by modules. * + * @param $theme_name + * The name of the theme whose blocks should be updated. If NULL, updates + * blocks for all enabled themes. + * * @return * Blocks currently exported by modules. + * An array of blocks for themes, keyed by theme names. */ -function _block_rehash() { - global $theme_key; - - drupal_theme_initialize(); +function block_rebuild($theme_name = NULL) { + $theme = array(); + // Build array of themes whose blocks need to be rebuilt. + if (is_null($theme_name)) { + foreach(list_themes() as $theme) { + if ($theme->status || $theme->name == variable_get('admin_theme', '0')) { + $themes[] = $theme->name; + } + } + // If rebuilding blocks for all themes select all blocks. + $result = db_query('SELECT * FROM {block}'); + } + else { + // If rebuilding blocks for a specific theme then select that specific + // themes blocks. + $themes = array($theme_name); + $result = db_query('SELECT * FROM {block} WHERE theme = :theme', array(':theme' => $theme_name)); + } $old_blocks = array(); - $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $theme_key)); + $result->setFetchMode(PDO::FETCH_ASSOC); foreach ($result as $old_block) { $old_block = is_object($old_block) ? get_object_vars($old_block) : $old_block; - $old_blocks[$old_block['module']][$old_block['delta']] = $old_block; + $old_blocks[$old_block['theme']][$old_block['module']][$old_block['delta']] = $old_block; } $blocks = array(); - // Valid region names for the theme. - $regions = system_region_list($theme_key); - foreach (module_implements('block_info') as $module) { $module_blocks = module_invoke($module, 'block_info'); if ($module_blocks) { - foreach ($module_blocks as $delta => $block) { - if (empty($old_blocks[$module][$delta])) { - // If it's a new block, add identifiers. - $block['module'] = $module; - $block['delta'] = $delta; - $block['theme'] = $theme_key; - if (!isset($block['pages'])) { - // {block}.pages is type 'text', so it cannot have a - // default value, and not null, so we need to provide - // value if the module did not. - $block['pages'] = ''; - } - // Add defaults and save it into the database. - drupal_write_record('block', $block); - // Set region to none if not enabled. - $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE; - // Add to the list of blocks we return. - $blocks[] = $block; - } - else { - // If it's an existing block, database settings should overwrite - // the code. But aside from 'info' everything that's definable in - // code is stored in the database and we do not store 'info', so we - // do not need to update the database here. - // Add 'info' to this block. - $old_blocks[$module][$delta]['info'] = $block['info']; - // If the region name does not exist, disable the block and assign it to none. - if (!empty($old_blocks[$module][$delta]['region']) && !isset($regions[$old_blocks[$module][$delta]['region']])) { - drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $old_blocks[$module][$delta]['info'], '%region' => $old_blocks[$module][$delta]['region'])), 'warning'); - $old_blocks[$module][$delta]['status'] = 0; - $old_blocks[$module][$delta]['region'] = BLOCK_REGION_NONE; + foreach($themes as $theme) { + // Valid region names for the theme. + $regions = system_region_list($theme); + foreach ($module_blocks as $delta => $block) { + if (empty($old_blocks[$theme][$module][$delta])) { + // If it's a new block, add identifiers. + $block['module'] = $module; + $block['delta'] = $delta; + $block['theme'] = $theme; + if (!isset($block['pages'])) { + // {block}.pages is type 'text', so it cannot have a + // default value, and not null, so we need to provide + // value if the module did not. + $block['pages'] = ''; + } + // Add defaults and save it into the database. + drupal_write_record('block', $block); + // Set region to none if not enabled. + $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE; + // Add to the list of blocks we return. + $blocks[$theme][] = $block; } else { - $old_blocks[$module][$delta]['region'] = $old_blocks[$module][$delta]['status'] ? $old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE; + $old_block = $old_blocks[$theme][$module][$delta]; + // For existing block, database settings should overwrite the code, + // except for possible changes in the cache mode. + if ((!isset($block['cache']) && $old_block['cache'] != BLOCK_CACHE_PER_ROLE) || (isset($block['cache']) && $old_block['cache'] != $block['cache'])) { + $old_block['cache'] = isset($block['cache']) ? $block['cache'] : BLOCK_CACHE_PER_ROLE; + drupal_write_record('block', $old_block, array('module', 'delta', 'theme')); + cache_clear_all("$module:$delta:", 'cache_block', TRUE); + } + // 'info' is the only thing that's definable in code but not stored + // in the database. + $old_block['info'] = $block['info']; + // If the region name does not exist, disable the block and assign it to none. + if (!empty($old_block['region']) && !isset($regions[$old_block['region']])) { + drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $old_block['info'], '%region' => $old_block['region'])), 'warning'); + $old_block['status'] = 0; + $old_block['region'] = BLOCK_REGION_NONE; + } + else { + $old_block['region'] = $old_block['status'] ? $old_block['region'] : BLOCK_REGION_NONE; + } + // Add this block to the list of blocks we return. + $blocks[$theme][] = $old_block; + // Remove this block from the list of blocks to be deleted. + unset($old_blocks[$theme][$module][$delta]); } - // Add this block to the list of blocks we return. - $blocks[] = $old_blocks[$module][$delta]; - // Remove this block from the list of blocks to be deleted. - unset($old_blocks[$module][$delta]); } } } } // Remove blocks that are no longer defined by the code from the database. - foreach ($old_blocks as $module => $old_module_blocks) { - foreach ($old_module_blocks as $delta => $block) { - db_delete('block') - ->condition('module', $module) - ->condition('delta', $delta) - ->condition('theme', $theme_key) - ->execute(); + foreach ($old_blocks as $theme => $old_theme_blocks) { + foreach ($old_theme_blocks as $module => $old_module_blocks) { + foreach ($old_module_blocks as $delta => $block) { + db_delete('block') + ->condition('module', $module) + ->condition('delta', $delta) + ->condition('theme', $theme) + ->execute(); + } } } - return $blocks; + + return is_null($theme_name) ? $blocks : $blocks[$theme_name]; } function block_custom_block_get($bid) { Index: modules/block/block.test =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.test,v retrieving revision 1.27 diff -u -p -r1.27 block.test --- modules/block/block.test 28 Aug 2009 19:44:05 -0000 1.27 +++ modules/block/block.test 21 Sep 2009 18:25:27 -0000 @@ -46,9 +46,9 @@ class BlockTestCase extends DrupalWebTes // Confirm that the custom block has been created, and then query the created bid. $this->assertText(t('The block has been created.'), t('Custom block successfully created.')); - $bid = db_query("SELECT bid FROM {block_custom} WHERE info = :info", array(':info' => $custom_block['info']))->fetchField(); + $bid = db_query('SELECT bid FROM {block_custom} WHERE info = :info', array(':info' => $custom_block['info']))->fetchField(); - // Check to see if the custom block was created by checking that it's in the database.. + // Check to see if the custom block was created by checking that it's in the database. $this->assertNotNull($bid, t('Custom block found in database')); // Check if the block can be moved to all availble regions. @@ -163,7 +163,7 @@ class BlockTestCase extends DrupalWebTes // Check to see if the block was created by checking that it's in the database. $this->assertNotNull($bid, t('Block found in database')); - // Check if the block can be moved to all availble regions. + // Check if the block can be moved to all available regions. foreach ($this->regions as $region) { $this->moveBlockToRegion($block, $region); } @@ -214,6 +214,76 @@ class BlockTestCase extends DrupalWebTes } } +/** + * Test block caching behavior. + */ +class BlockCachingTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Block caching', + 'description' => 'Test various aspects of the block caching system.', + 'group' => 'Block', + ); + } + + function setUp() { + parent::setUp('block_test'); + + // Create and login user + $admin_user = $this->drupalCreateUser(array('administer blocks')); + $this->drupalLogin($admin_user); + } + + /** + * Validate the behavior of the block caching layer. + */ + function testCaching() { + variable_set('block_cache', 1); + variable_set('block_test_content', $this->randomName(20)); + + // Display the test block. + $edit = array(); + $edit['block_test_test_block[region]'] = 'left'; + $this->drupalPost('admin/build/block', $edit, t('Save blocks')); + + // Confirm that the test block is displayed. + $this->assertText(variable_get('block_test_content', ''), t('(NO_CACHE) Test block successfully being displayed on the page.')); + + // Try changing the test block contents. + variable_set('block_test_content', $this->randomName(20)); + $this->drupalGet(''); + $this->assertText(variable_get('block_test_content', ''), t('(NO_CACHE) Test block content successfully changed.')); + + // Change the caching of the test block. + variable_set('block_test_caching', BLOCK_CACHE_GLOBAL); + $this->drupalPost('admin/build/block', array(), t('Save blocks')); + + // Try changing the test block contents. + $this->drupalGet(''); + $this->assertText(variable_get('block_test_content', ''), t('(CACHE_GLOBAL) Test block content is still there.')); + variable_set('block_test_content', $data = $this->randomName(20)); + $this->drupalGet(''); + $this->assertNoText(variable_get('block_test_content', ''), t('(CACHE_GLOBAL) Test block content has been cached.')); + + // Empty caches. + cache_clear_all(NULL, 'cache_block'); + $this->drupalGet(''); + $this->assertText(variable_get('block_test_content', ''), t('(CACHE_GLOBAL) Test block content changed after cache_clear_all().')); + + // Back to no caching. + variable_set('block_test_caching', BLOCK_NO_CACHE); + $this->drupalPost('admin/build/block', array(), t('Save blocks')); + + // Try changing the test block contents. + $this->drupalGet(''); + $this->assertText(variable_get('block_test_content', ''), t('(NO_CACHE) Test block content is still there.')); + variable_set('block_test_content', $this->randomName(20)); + $this->drupalGet(''); + $this->assertText(variable_get('block_test_content', ''), t('(NO_CACHE) Test block content successfully changed.')); + } +} + class NonDefaultBlockAdmin extends DrupalWebTestCase { public static function getInfo() { return array( Index: modules/simpletest/tests/block_test.info =================================================================== RCS file: modules/simpletest/tests/block_test.info diff -N modules/simpletest/tests/block_test.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/simpletest/tests/block_test.info 21 Sep 2009 18:25:27 -0000 @@ -0,0 +1,7 @@ +; $Id$ +name = "Block Test" +description = "Support module for testing the Block module." +package = Testing +core = 7.x +files[] = block_test.module +hidden = TRUE Index: modules/simpletest/tests/block_test.module =================================================================== RCS file: modules/simpletest/tests/block_test.module diff -N modules/simpletest/tests/block_test.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/simpletest/tests/block_test.module 21 Sep 2009 18:25:27 -0000 @@ -0,0 +1,30 @@ + t('Test block'), + 'cache' => variable_get('block_test_caching', BLOCK_NO_CACHE), + ); + return $blocks; +} + +/** + * Implementat hook_block_view(). + */ +function block_test_block_view($delta = 0, $edit = array()) { + if ($delta == 'test_block') { + return array( + 'subject' => t('Test block'), + 'content' => variable_get('block_test_content', ''), + ); + } +}