diff --git a/core/lib/Drupal/Component/Plugin/FallbackPluginManagerInterface.php b/core/lib/Drupal/Component/Plugin/FallbackPluginManagerInterface.php index 552000faf40e9dbeabb733586ea6fdbef46a33ad..25c31e6342318c1fa6391dd21624898d1dccdb84 100644 --- a/core/lib/Drupal/Component/Plugin/FallbackPluginManagerInterface.php +++ b/core/lib/Drupal/Component/Plugin/FallbackPluginManagerInterface.php @@ -21,7 +21,7 @@ interface FallbackPluginManagerInterface { * An array of configuration relevant to the plugin instance. * * @return string - * The id of an existing plugin to use for ... why isn't this in the factory? + * The id of an existing plugin to use when the plugin does not exist. */ public function getFallbackPluginId($plugin_id, array $configuration = array()); diff --git a/core/lib/Drupal/Core/Block/BlockManager.php b/core/lib/Drupal/Core/Block/BlockManager.php index 8cde72804d3281e089ab6035c39f60d9a6a36112..75f952719edbe59f22d3178cf1c19518ed314351 100644 --- a/core/lib/Drupal/Core/Block/BlockManager.php +++ b/core/lib/Drupal/Core/Block/BlockManager.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Block; +use Drupal\Component\Plugin\FallbackPluginManagerInterface; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait; @@ -20,7 +21,7 @@ * * @see \Drupal\Core\Block\BlockPluginInterface */ -class BlockManager extends DefaultPluginManager implements BlockManagerInterface { +class BlockManager extends DefaultPluginManager implements BlockManagerInterface, FallbackPluginManagerInterface { use StringTranslationTrait; use ContextAwarePluginManagerTrait; @@ -108,7 +109,16 @@ public function getSortedDefinitions() { } return strnatcasecmp($a['admin_label'], $b['admin_label']); }); + // Do not display the 'broken' plugin in the UI. + unset($definitions['broken']); return $definitions; } + /** + * {@inheritdoc} + */ + public function getFallbackPluginId($plugin_id, array $configuration = array()) { + return 'broken'; + } + } diff --git a/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php b/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php new file mode 100644 index 0000000000000000000000000000000000000000..df61f3bd9023f0487338efdd3d53a0282cd0dc37 --- /dev/null +++ b/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php @@ -0,0 +1,52 @@ +<?php + +/** + * @file + * Contains \Drupal\Core\Block\Plugin\Block\Broken. + */ + +namespace Drupal\Core\Block\Plugin\Block; + +use Drupal\Core\Block\BlockBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Defines a fallback plugin for missing block plugins. + * + * @Block( + * id = "broken", + * admin_label = @Translation("Broken/Missing"), + * category = @Translation("Block"), + * ) + */ +class Broken extends BlockBase { + + /** + * {@inheritdoc} + */ + public function build() { + return $this->brokenMessage(); + } + + /** + * {@inheritdoc} + */ + public function blockForm($form, FormStateInterface $form_state) { + return $this->brokenMessage(); + } + + /** + * Generate message with debugging information as to why the block is broken. + * + * @return array + * Render array containing debug information. + */ + protected function brokenMessage() { + $build['message'] = [ + '#markup' => $this->t('This block is broken or missing. You may be missing content or you might need to enable the original module.') + ]; + + return $build; + } + +} diff --git a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php index 3db1a1c2457eaee862e8f296dc24123ae2c7faa6..51ea7e5aa0263f15815285d88ef84c5e1536ccea 100644 --- a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php +++ b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php @@ -124,7 +124,7 @@ public function defaultConfiguration() { * Adds body and description fields to the block configuration form. */ public function blockForm($form, FormStateInterface $form_state) { - $form['block_content']['view_mode'] = array( + $form['view_mode'] = array( '#type' => 'select', '#options' => $this->entityManager->getViewModeOptions('block_content'), '#title' => t('View mode'), @@ -141,7 +141,7 @@ public function blockForm($form, FormStateInterface $form_state) { public function blockSubmit($form, FormStateInterface $form_state) { // Invalidate the block cache to update custom block-based derivatives. if ($this->moduleHandler->moduleExists('block')) { - $this->configuration['view_mode'] = $form_state->getValue(array('block_content', 'view_mode')); + $this->configuration['view_mode'] = $form_state->getValue('view_mode'); $this->blockManager->clearCachedDefinitions(); } } diff --git a/core/modules/block_content/src/Tests/BlockContentCreationTest.php b/core/modules/block_content/src/Tests/BlockContentCreationTest.php index 93704cd630e675cf7f575e6b2655e4e68f12dec3..7956d1d4ce4ebe31750bc09d1584aac0635ee1c8 100644 --- a/core/modules/block_content/src/Tests/BlockContentCreationTest.php +++ b/core/modules/block_content/src/Tests/BlockContentCreationTest.php @@ -63,15 +63,15 @@ public function testBlockContentCreation() { )), 'Basic block created.'); // Change the view mode. - $view_mode['settings[block_content][view_mode]'] = 'test_view_mode'; + $view_mode['settings[view_mode]'] = 'test_view_mode'; $this->drupalPostForm(NULL, $view_mode, t('Save block')); // Go to the configure page and verify that the new view mode is correct. $this->drupalGet('admin/structure/block/manage/testblock'); - $this->assertFieldByXPath('//select[@name="settings[block_content][view_mode]"]/option[@selected="selected"]/@value', 'test_view_mode', 'View mode changed to Test View Mode'); + $this->assertFieldByXPath('//select[@name="settings[view_mode]"]/option[@selected="selected"]/@value', 'test_view_mode', 'View mode changed to Test View Mode'); // Test the available view mode options. - $this->assertOption('edit-settings-block-content-view-mode', 'default', 'The default view mode is available.'); + $this->assertOption('edit-settings-view-mode', 'default', 'The default view mode is available.'); // Check that the block exists in the database. $blocks = entity_load_multiple_by_properties('block_content', array('info' => $edit['info[0][value]'])); diff --git a/core/modules/block_content/src/Tests/BlockContentPageViewTest.php b/core/modules/block_content/src/Tests/BlockContentPageViewTest.php index 9d575288041819a4c66eceda2733677a57792765..90adab71253373ca3e5ebff441d6727f4cec9c78 100644 --- a/core/modules/block_content/src/Tests/BlockContentPageViewTest.php +++ b/core/modules/block_content/src/Tests/BlockContentPageViewTest.php @@ -22,7 +22,7 @@ class BlockContentPageViewTest extends BlockContentTestBase { public static $modules = array('block', 'block_content', 'block_content_test'); /** - * Checks block edit functionality. + * Checks block edit and fallback functionality. */ public function testPageEdit() { $this->drupalLogin($this->adminUser); @@ -33,6 +33,8 @@ public function testPageEdit() { // Assert response was '200' and not '403 Access denied'. $this->assertResponse('200', 'User was able the view the block'); + $this->drupalGet('<front>'); + $this->assertRaw(t('This block is broken or missing. You may be missing content or you might need to enable the original module.')); } } diff --git a/core/modules/block_content/tests/modules/block_content_test/config/install/block.block.foobargorilla.yml b/core/modules/block_content/tests/modules/block_content_test/config/install/block.block.foobargorilla.yml new file mode 100644 index 0000000000000000000000000000000000000000..b8b7827fa1e7dba0c8fe4ee0d140557a707f1b84 --- /dev/null +++ b/core/modules/block_content/tests/modules/block_content_test/config/install/block.block.foobargorilla.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + module: + - block_content + theme: + - stark +id: foobargorilla +theme: stark +region: content +weight: null +provider: null +plugin: 'block_content:fb5e8434-3617-4a1d-a252-8273e95ec30e' +settings: + visibility: + request_path: + id: request_path + pages: '' + negate: false + id: 'block_content:fb5e8434-3617-4a1d-a252-8273e95ec30e' + label: 'Foobar Gorilla' + provider: block_content + label_display: visible + cache: + max_age: -1 + contexts: { } + status: true + info: '' + view_mode: default