Issue #1881096 by mradcliffe, xjm, EclipseGc: Fixed Regression: Site broken when disabling module without removing block instances.

8.0.x
webchick 2013-01-08 13:01:41 -08:00
parent 97c3ee2be9
commit 55d72f73be
2 changed files with 125 additions and 5 deletions

View File

@ -5,6 +5,8 @@
* Controls the visual building blocks a page is constructed with.
*/
use Drupal\Component\Plugin\Exception\PluginException;
/**
* Denotes that a block is not enabled in any region and should not be shown.
*/
@ -361,7 +363,11 @@ function _block_rehash($theme = NULL) {
$block_configs = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
$regions = system_region_list($theme);
foreach ($block_configs as $config) {
$blocks[$config] = block_load($config);
// Only list valid block instances.
if (!$block = block_load($config)) {
continue;
}
$blocks[$config] = $block;
$config = config($config);
$region = $config->get('region');
$status = $config->get('status');
@ -472,11 +478,25 @@ function block_list($region) {
*
* @return
* A block object.
*
* @todo Add block_load_multiple() and make this function a single-value wrapper.
*/
function block_load($plugin_id, array $conf = array()) {
$manager = drupal_container()->get('plugin.manager.block');
if (!$block = $manager->getInstance(array('config' => $plugin_id))) {
$block = $manager->createInstance($plugin_id, $conf);
// If the block instance does not exist, try to create it.
try {
$block = $manager->createInstance($plugin_id, $conf);
}
catch (PluginException $e) {
$config = config($plugin_id)->get();
// Ignore blocks belonging to disabled modules, but re-throw valid
// exceptions when the module is enabled and the plugin is misconfigured.
if (empty($config['module']) || module_exists($config['module'])) {
throw $e;
}
return FALSE;
}
}
return $block;
}
@ -486,6 +506,8 @@ function block_load($plugin_id, array $conf = array()) {
*
* @return
* An array of blocks grouped by region.
*
* @todo Remove this function, and replace it with a block_load_multiple().
*/
function _block_load_blocks() {
global $theme;
@ -493,9 +515,10 @@ function _block_load_blocks() {
$instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
$manager = drupal_container()->get('plugin.manager.block');
foreach ($instances as $plugin_id) {
$block = $manager->getInstance(array('config' => $plugin_id));
$config = $block->getConfig();
$blocks[$config['region']]["$plugin_id"] = $block;
if ($block = block_load($plugin_id)) {
$config = $block->getConfig();
$blocks[$config['region']]["$plugin_id"] = $block;
}
}
return $blocks;
}

View File

@ -379,4 +379,101 @@ class BlockTest extends WebTestBase {
$config = $instance->getConfig();
$this->assertEqual($config['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
}
/**
* Tests blocks belonging to disabled modules.
*/
function testBlockModuleDisable() {
module_enable(array('block_test'));
$this->assertTrue(module_exists('block_test'), 'Test block module enabled.');
// Clear the block cache to load the block_test module's block definitions.
$manager = $this->container->get('plugin.manager.block');
$manager->clearCachedDefinitions();
// Add test blocks in different regions and confirm they are displayed.
$blocks = array();
$regions = array('sidebar_first', 'content', 'footer');
foreach ($regions as $region) {
$blocks[$region] = $this->drupalPlaceBlock('test_cache', array('region' => $region));
}
$this->drupalGet('');
foreach ($regions as $region) {
$this->assertText($blocks[$region]['subject']);
}
// Disable the block test module and refresh the definitions cache.
module_disable(array('block_test'), FALSE);
$this->assertFalse(module_exists('block_test'), 'Test block module disabled.');
$manager->clearCachedDefinitions();
// Ensure that the block administration page still functions as expected.
$this->drupalGet('admin/structure/block');
$this->assertResponse(200);
// A 200 response is possible with a fatal error, so check the title too.
$this->assertTitle(t('Blocks | Drupal'));
// Ensure that the disabled module's block instance is not listed.
foreach ($regions as $region) {
$this->assertNoText($blocks[$region]['subject']);
}
// Ensure that the disabled module's block plugin is no longer available.
$this->drupalGet('admin/structure/block/list/block_plugin_ui:' . variable_get('theme_default', 'stark') . '/add');
$this->assertNoText(t('Test block caching'));
// Confirm that the block is no longer displayed on the front page.
$this->drupalGet('');
$this->assertResponse(200);
foreach ($regions as $region) {
$this->assertNoText($blocks[$region]['subject']);
}
// Confirm that a different block instance can still be enabled by
// submitting the block library form.
// Emulate a POST submission rather than using drupalPlaceBlock() to ensure
// that the form still functions as expected.
$edit = array(
'title' => $this->randomName(8),
'machine_name' => $this->randomName(8),
'region' => 'sidebar_first',
);
$this->drupalPost('admin/structure/block/manage/system_powered_by_block/stark', $edit, t('Save block'));
$this->assertText(t('The block configuration has been saved.'));
$this->assertText($edit['title']);
// Update the weight of a block.
$edit = array('blocks[0][weight]' => -1);
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
$this->assertText(t('The block settings have been updated.'));
// Re-enable the module and refresh the definitions cache.
module_enable(array('block_test'), FALSE);
$this->assertTrue(module_exists('block_test'), 'Test block module re-enabled.');
$manager->clearCachedDefinitions();
// Reload the admin page and confirm the block can again be configured.
$this->drupalGet('admin/structure/block');
foreach ($regions as $region) {
$this->assertLinkByHref(url('admin/structure/block/manage/' . $blocks[$region]['config_id'] . '/stark/config'));
}
// Confirm that the blocks are again displayed on the front page in the
// correct regions.
$this->drupalGet('');
foreach ($regions as $region) {
// @todo Use a proper method for this.
$name_pieces = explode('.', $blocks[$region]['config_id']);
$machine_name = array_pop($name_pieces);
$xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
':region-class' => 'region region-' . drupal_html_class($region),
':block-id' => 'block-' . strtr(strtolower($machine_name), '-', '_'),
));
$this->assertFieldByXPath($xpath, NULL, format_string('Block %name found in the %region region.', array(
'%name' => $blocks[$region]['subject'],
'%region' => $region,
)));
}
}
}