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. * 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. * 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); $block_configs = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
$regions = system_region_list($theme); $regions = system_region_list($theme);
foreach ($block_configs as $config) { 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); $config = config($config);
$region = $config->get('region'); $region = $config->get('region');
$status = $config->get('status'); $status = $config->get('status');
@ -472,11 +478,25 @@ function block_list($region) {
* *
* @return * @return
* A block object. * A block object.
*
* @todo Add block_load_multiple() and make this function a single-value wrapper.
*/ */
function block_load($plugin_id, array $conf = array()) { function block_load($plugin_id, array $conf = array()) {
$manager = drupal_container()->get('plugin.manager.block'); $manager = drupal_container()->get('plugin.manager.block');
if (!$block = $manager->getInstance(array('config' => $plugin_id))) { 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; return $block;
} }
@ -486,6 +506,8 @@ function block_load($plugin_id, array $conf = array()) {
* *
* @return * @return
* An array of blocks grouped by region. * An array of blocks grouped by region.
*
* @todo Remove this function, and replace it with a block_load_multiple().
*/ */
function _block_load_blocks() { function _block_load_blocks() {
global $theme; global $theme;
@ -493,9 +515,10 @@ function _block_load_blocks() {
$instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme); $instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
$manager = drupal_container()->get('plugin.manager.block'); $manager = drupal_container()->get('plugin.manager.block');
foreach ($instances as $plugin_id) { foreach ($instances as $plugin_id) {
$block = $manager->getInstance(array('config' => $plugin_id)); if ($block = block_load($plugin_id)) {
$config = $block->getConfig(); $config = $block->getConfig();
$blocks[$config['region']]["$plugin_id"] = $block; $blocks[$config['region']]["$plugin_id"] = $block;
}
} }
return $blocks; return $blocks;
} }

View File

@ -379,4 +379,101 @@ class BlockTest extends WebTestBase {
$config = $instance->getConfig(); $config = $instance->getConfig();
$this->assertEqual($config['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE."); $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,
)));
}
}
} }