From 84b902eb6c0303a906ec3f194bf4b26ce4a42e2e Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Sat, 2 Jun 2018 15:44:14 +0200
Subject: [PATCH] Issue #2966969 by tim.plunkett, msankhala, alexpott: Trigger
 a warning whenever the "Broken" block plugin is instantiated

---
 core/core.services.yml                        |  1 +
 .../Component/Plugin/PluginManagerBase.php    | 19 +++++++++++++--
 core/lib/Drupal/Core/Block/BlockManager.php   | 21 ++++++++++++++++-
 .../Tests/Core/Block/BlockManagerTest.php     | 23 ++++++++++++++++++-
 4 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/core/core.services.yml b/core/core.services.yml
index c58c15d7bb86..680c23b80840 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -608,6 +608,7 @@ services:
   plugin.manager.block:
     class: Drupal\Core\Block\BlockManager
     parent: default_plugin_manager
+    arguments: ['@logger.channel.default']
   plugin.manager.field.field_type:
     class: Drupal\Core\Field\FieldTypePluginManager
     arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@typed_data_manager']
diff --git a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
index 34416ff4371d..bc285e501f0f 100644
--- a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
+++ b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
@@ -76,8 +76,7 @@ public function createInstance($plugin_id, array $configuration = []) {
         return $this->getFactory()->createInstance($plugin_id, $configuration);
       }
       catch (PluginNotFoundException $e) {
-        $fallback_id = $this->getFallbackPluginId($plugin_id, $configuration);
-        return $this->getFactory()->createInstance($fallback_id, $configuration);
+        return $this->handlePluginNotFound($plugin_id, $configuration);
       }
     }
     else {
@@ -85,6 +84,22 @@ public function createInstance($plugin_id, array $configuration = []) {
     }
   }
 
+  /**
+   * Allows plugin managers to specify custom behavior if a plugin is not found.
+   *
+   * @param string $plugin_id
+   *   The ID of the missing requested plugin.
+   * @param array $configuration
+   *   An array of configuration relevant to the plugin instance.
+   *
+   * @return object
+   *   A fallback plugin instance.
+   */
+  protected function handlePluginNotFound($plugin_id, array $configuration) {
+    $fallback_id = $this->getFallbackPluginId($plugin_id, $configuration);
+    return $this->getFactory()->createInstance($fallback_id, $configuration);
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Block/BlockManager.php b/core/lib/Drupal/Core/Block/BlockManager.php
index 467e63565ef1..026d810fc058 100644
--- a/core/lib/Drupal/Core/Block/BlockManager.php
+++ b/core/lib/Drupal/Core/Block/BlockManager.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Plugin\CategorizingPluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Plugin\FilteredPluginManagerTrait;
+use Psr\Log\LoggerInterface;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -23,6 +24,13 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
   }
   use FilteredPluginManagerTrait;
 
+  /**
+   * The logger.
+   *
+   * @var \Psr\Log\LoggerInterface
+   */
+  protected $logger;
+
   /**
    * Constructs a new \Drupal\Core\Block\BlockManager object.
    *
@@ -33,12 +41,15 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Psr\Log\LoggerInterface $logger
+   *   The logger.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LoggerInterface $logger) {
     parent::__construct('Plugin/Block', $namespaces, $module_handler, 'Drupal\Core\Block\BlockPluginInterface', 'Drupal\Core\Block\Annotation\Block');
 
     $this->alterInfo($this->getType());
     $this->setCacheBackend($cache_backend, 'block_plugins');
+    $this->logger = $logger;
   }
 
   /**
@@ -74,4 +85,12 @@ public function getFallbackPluginId($plugin_id, array $configuration = []) {
     return 'broken';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function handlePluginNotFound($plugin_id, array $configuration) {
+    $this->logger->warning('The "%plugin_id" was not found', ['%plugin_id' => $plugin_id]);
+    return parent::handlePluginNotFound($plugin_id, $configuration);
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php b/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php
index 1e9bb436db5d..0f92b8efbc62 100644
--- a/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php
@@ -4,9 +4,11 @@
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 use Drupal\Core\Block\BlockManager;
+use Drupal\Core\Block\Plugin\Block\Broken;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Tests\UnitTestCase;
+use Psr\Log\LoggerInterface;
 
 /**
  * @coversDefaultClass \Drupal\Core\Block\BlockManager
@@ -22,6 +24,13 @@ class BlockManagerTest extends UnitTestCase {
    */
   protected $blockManager;
 
+  /**
+   * The logger.
+   *
+   * @var \Psr\Log\LoggerInterface
+   */
+  protected $logger;
+
   /**
    * {@inheritdoc}
    */
@@ -30,7 +39,8 @@ protected function setUp() {
 
     $cache_backend = $this->prophesize(CacheBackendInterface::class);
     $module_handler = $this->prophesize(ModuleHandlerInterface::class);
-    $this->blockManager = new BlockManager(new \ArrayObject(), $cache_backend->reveal(), $module_handler->reveal());
+    $this->logger = $this->prophesize(LoggerInterface::class);
+    $this->blockManager = new BlockManager(new \ArrayObject(), $cache_backend->reveal(), $module_handler->reveal(), $this->logger->reveal());
     $this->blockManager->setStringTranslation($this->getStringTranslationStub());
 
     $discovery = $this->prophesize(DiscoveryInterface::class);
@@ -40,6 +50,8 @@ protected function setUp() {
       'broken' => [
         'admin_label' => 'Broken/Missing',
         'category' => 'Block',
+        'class' => Broken::class,
+        'provider' => 'core',
       ],
       'block1' => [
         'admin_label' => 'Coconut',
@@ -86,4 +98,13 @@ public function testGroupedDefinitions() {
     $this->assertSame(['block3', 'block1'], array_keys($definitions['Group 2']));
   }
 
+  /**
+   * @covers ::handlePluginNotFound
+   */
+  public function testHandlePluginNotFound() {
+    $this->logger->warning('The "%plugin_id" was not found', ['%plugin_id' => 'invalid'])->shouldBeCalled();
+    $plugin = $this->blockManager->createInstance('invalid');
+    $this->assertSame('broken', $plugin->getPluginId());
+  }
+
 }
-- 
GitLab