diff --git a/modules/block/block.module b/modules/block/block.module index 3a988de..9ebbcc5 100644 --- a/modules/block/block.module +++ b/modules/block/block.module @@ -401,23 +401,36 @@ function _block_rehash($theme = NULL) { } // Save the blocks defined in code for alter context. $code_blocks = $current_blocks; - $database_blocks = db_select('block', 'b') + $database_blocks = db_select('block', 'b', array('fetch' => PDO::FETCH_ASSOC)) ->fields('b') ->condition($or) ->condition('theme', $theme) ->execute(); + $original_database_blocks = array(); + $alter_implemented = (bool) module_implements('block_info_alter'); foreach ($database_blocks as $block) { - // Preserve info which is not in the database. - $block->info = $current_blocks[$block->module][$block->delta]['info']; + $module = $block['module']; + $delta = $block['delta']; + // The copy is needed later only if the alter hook implemented, otherwise + // it is possible to keep track of changes inside this function. + if ($alter_implemented) { + $original_database_blocks[$module][$delta] = $block; + } // The cache mode can only by set from hook_block_info(), so that has // precedence over the database's value. - if (isset($current_blocks[$block->module][$block->delta]['cache'])) { - $block->cache = $current_blocks[$block->module][$block->delta]['cache']; + $cache = $block['cache']; + if (isset($current_blocks[$module][$delta]['cache'])) { + $block['cache'] = $current_blocks[$module][$delta]['cache']; + if ($cache != $block['cache']) { + $changed_blocks[$module][$delta] = TRUE; + } } + // Preserve info which is not in the database. + $block['info'] = $current_blocks[$module][$delta]['info']; // Blocks stored in the database override the blocks defined in code. - $current_blocks[$block->module][$block->delta] = get_object_vars($block); + $current_blocks[$module][$delta] = $block; // Preserve this block. - $bids[$block->bid] = $block->bid; + $bids[$block['bid']] = $block['bid']; } drupal_alter('block_info', $current_blocks, $theme, $code_blocks); foreach ($current_blocks as $module => $module_blocks) { @@ -437,6 +450,8 @@ function _block_rehash($theme = NULL) { // Disabled modules are moved into the BLOCK_REGION_NONE later so no // need to move the block to another region. $block['status'] = 0; + // This change needs to be recorded in the database. + $changed_blocks[$module][$delta] = TRUE; } // Set region to none if not enabled and make sure status is set. if (empty($block['status'])) { @@ -456,7 +471,15 @@ function _block_rehash($theme = NULL) { else { $primary_keys = array(); } - drupal_write_record('block', $block, $primary_keys); + // If the block is new, changed in this function or in the alter hook + // then save it. To determine whether there was a change during alter, + // it is enough to examine the values for the keys in the original + // database record as that contained every database field. + if (!$primary_keys || !empty($changed_blocks[$module][$delta]) || ($alter_implemented && array_diff_assoc($original_database_blocks[$module][$delta], $block))) { + drupal_write_record('block', $block, $primary_keys); + // Make it possible to test this. + $block['saved'] = TRUE; + } // Add to the list of blocks we return. $blocks[] = $block; } diff --git a/modules/block/block.test b/modules/block/block.test index 11d0709..45c63d8 100644 --- a/modules/block/block.test +++ b/modules/block/block.test @@ -193,7 +193,7 @@ class BlockTestCase extends DrupalWebTestCase { } /** - * Test block visibility when using "pages" restriction but leaving + * Test block visibility when using "pages" restriction but leaving * "pages" textarea empty */ function testBlockVisibilityListedEmpty() { @@ -857,3 +857,57 @@ class BlockInvalidRegionTestCase extends DrupalWebTestCase { $this->assertNoRaw($warning_message, 'Disabled block in the invalid region will not trigger the warning.'); } } + +class BlockHashTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Block rehash', + 'description' => 'Checks _block_rehash() functionality.', + 'group' => 'Block', + ); + } + + function setUp() { + parent::setUp(array('block')); + } + + function testBlockRehash() { + // No hook_block_info_alter(), no save. + $this->doRehash(); + module_enable(array('block_test'), FALSE); + // Save the new blocks, check that the new blocks exist by checking weight. + _block_rehash(); + $this->assertWeight(0); + // Now hook_block_info_alter() exists but no blocks are saved on a second + // rehash. + $this->doRehash(); + $this->assertWeight(0); + // Now hook_block_info_alter() exists and is changing one block which + // should be saved. + $GLOBALS['conf']['block_test_info_alter'] = 1; + $this->doRehash(TRUE); + $this->assertWeight(10000); + } + + function doRehash($alter_active = FALSE) { + $saves = 0; + foreach (_block_rehash() as $block) { + $module = $block['module']; + $delta = $block['delta']; + if ($alter_active && $module == 'block_test' && $delta == 'test_html_id') { + $this->assertFalse(empty($block['saved']), "$module $delta saved"); + $saves++; + } + else { + $this->assertTrue(empty($block['saved']), "$module $delta not saved"); + } + } + $this->assertEqual($alter_active, $saves); + } + + function assertWeight($weight) { + $db_weight = db_query('SELECT weight FROM {block} WHERE module = :module AND delta = :delta', array(':module' => 'block_test', ':delta' => 'test_html_id'))->fetchField(); + // By casting to string the assert fails on FALSE. + $this->assertIdentical((string) $db_weight, (string) $weight); + } +} diff --git a/modules/block/tests/block_test.module b/modules/block/tests/block_test.module index 5e06d5c..abd77b8 100644 --- a/modules/block/tests/block_test.module +++ b/modules/block/tests/block_test.module @@ -34,3 +34,12 @@ function block_test_block_info() { function block_test_block_view($delta = 0) { return array('content' => variable_get('block_test_content', '')); } + +/** + * Implements hook_block_info_alter(). + */ +function block_test_block_info_alter(&$blocks) { + if (variable_get('block_test_info_alter')) { + $blocks['block_test']['test_html_id']['weight'] = 10000; + } +}