diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index bcc3954ae69baa19fd36221ef048ca80512ec128..02e5def894dc879a2ccf7ba84e19e9d4592a764f 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -11,6 +11,7 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Plugin\PluginWithFormsInterface; +use Drupal\Core\Plugin\PluginWithFormsTrait; use Drupal\Core\Session\AccountInterface; use Drupal\Component\Transliteration\TransliterationInterface; @@ -26,6 +27,7 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface { use ContextAwarePluginAssignmentTrait; + use PluginWithFormsTrait; /** * The transliteration service. @@ -272,20 +274,4 @@ public function setTransliteration(TransliterationInterface $transliteration) { $this->transliteration = $transliteration; } - /** - * {@inheritdoc} - */ - public function getFormClass($operation) { - if ($this->hasFormClass($operation)) { - return $this->getPluginDefinition()['forms'][$operation]; - } - } - - /** - * {@inheritdoc} - */ - public function hasFormClass($operation) { - return isset($this->getPluginDefinition()['forms'][$operation]); - } - } diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index fa706a47adc5b22efc2d868b7e16f69c7bf382e5..62decb22e876c347de94846efa7fd2ef4c37e52b 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -247,12 +247,6 @@ public function processDefinition(&$definition, $plugin_id) { if (!empty($this->defaults) && is_array($this->defaults)) { $definition = NestedArray::mergeDeep($this->defaults, $definition); } - - // If no default form is defined and this plugin implements - // \Drupal\Core\Plugin\PluginFormInterface, use that for the default form. - if (!isset($definition['forms']['configure']) && isset($definition['class']) && is_subclass_of($definition['class'], PluginFormInterface::class)) { - $definition['forms']['configure'] = $definition['class']; - } } /** diff --git a/core/lib/Drupal/Core/Plugin/PluginWithFormsTrait.php b/core/lib/Drupal/Core/Plugin/PluginWithFormsTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..ec717206c8d9d29549e60cb5079c17847ef96e99 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/PluginWithFormsTrait.php @@ -0,0 +1,29 @@ +getPluginDefinition()['forms'][$operation])) { + return $this->getPluginDefinition()['forms'][$operation]; + } + elseif ($operation === 'configure' && $this instanceof PluginFormInterface) { + return static::class; + } + } + + /** + * {@inheritdoc} + */ + public function hasFormClass($operation) { + return !empty($this->getFormClass($operation)); + } + +} diff --git a/core/modules/system/system.install b/core/modules/system/system.install index d705b5c25aeb444a1412de566339e0e2d5b5efe1..8ab78ffe8e8d2467996aec48084b2d0e1222d1a7 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1659,6 +1659,11 @@ function system_update_8014() { * @} End of "addtogroup updates-8.0.0-rc". */ +/** + * @addtogroup updates-8.2.0 + * @{ + */ + /** * Fix configuration overrides to not override non existing keys. */ @@ -1681,3 +1686,14 @@ function system_update_8200(&$sandbox) { $sandbox['config_names'] = array_diff($sandbox['config_names'], $config_names_to_process); $sandbox['#finished'] = empty($sandbox['config_names']) ? 1 : ($sandbox['max'] - count($sandbox['config_names'])) / $sandbox['max']; } + +/** + * Clear caches due to behavior change in DefaultPluginManager. + */ +function system_update_8201() { + // Empty update to cause a cache rebuild. +} + +/** + * @} End of "addtogroup updates-8.2.0". + */ diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/ExtendingNonInstalledClass.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/ExtendingNonInstalledClass.php new file mode 100644 index 0000000000000000000000000000000000000000..a42a474ed5359d9bad6fcea96c8de03d81a1a720 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/ExtendingNonInstalledClass.php @@ -0,0 +1,14 @@ + 'Drupal\plugin_test_extended\Plugin\plugin_test\fruit\BigApple', 'provider' => 'plugin_test_extended', ), + 'extending_non_installed_class' => array( + 'id' => 'extending_non_installed_class', + 'label' => 'A plugin whose class is extending from a non-installed module class', + 'color' => 'pink', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\ExtendingNonInstalledClass', + 'provider' => 'plugin_test', + ), ); $base_directory = \Drupal::root() . '/core/modules/system/tests/modules/plugin_test/src'; diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php index 3d5d8c264035a9a43cbeb5468993f00363f6e83d..a9fbf799eab8794ddaa478654020b80dbdfe1585 100644 --- a/core/tests/Drupal/KernelTests/Core/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php +++ b/core/tests/Drupal/KernelTests/Core/Plugin/Discovery/CustomDirectoryAnnotatedClassDiscoveryTest.php @@ -71,6 +71,13 @@ protected function setUp() { 'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Orange', 'provider' => 'plugin_test', ), + 'extending_non_installed_class' => array( + 'id' => 'extending_non_installed_class', + 'label' => 'A plugin whose class is extending from a non-installed module class', + 'color' => 'pink', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\ExtendingNonInstalledClass', + 'provider' => 'plugin_test', + ), ); $base_directory = \Drupal::root() . '/core/modules/system/tests/modules/plugin_test/src'; diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php index feac00467c2e3275f8b4f6a0979edb73f64a186a..ffdac5a37eaf014516ec7f441e0a2b99db5c15a2 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php @@ -60,6 +60,25 @@ protected function setUp() { $this->namespaces['Drupal\plugin_test'] = $this->root . '/core/modules/system/tests/modules/plugin_test/src'; } + /** + * Tests the plugin manager with a plugin that extends a non-installed class. + */ + public function testDefaultPluginManagerWithPluginExtendingNonInstalledClass() { + $definitions = array(); + $definitions['extending_non_installed_class'] = array( + 'id' => 'extending_non_installed_class', + 'label' => 'A plugin whose class is extending from a non-installed module class', + 'color' => 'pink', + 'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\ExtendingNonInstalledClass', + 'provider' => 'plugin_test', + ); + + $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); + $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface'); + $plugin_manager->getDefinition('plugin_test', FALSE); + $this->assertTrue(TRUE, 'No PHP fatal error occurred when retrieving the definitions of a module with plugins that depend on a non-installed module class should not cause a PHP fatal.'); + } + /** * Tests the plugin manager with a disabled module. */ @@ -383,7 +402,6 @@ public function providerTestProcessDefinition() { $data['no_form'][] = ['class' => TestPluginForm::class]; $data['no_form'][] = [ 'class' => TestPluginForm::class, - 'forms' => ['configure' => TestPluginForm::class], 'foo' => ['bar' => ['baz']], ]; diff --git a/core/tests/Drupal/Tests/Core/Plugin/PluginWithFormsTraitTest.php b/core/tests/Drupal/Tests/Core/Plugin/PluginWithFormsTraitTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7066f786dc3221ef4556c0cbf1687fe2d3507203 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Plugin/PluginWithFormsTraitTest.php @@ -0,0 +1,67 @@ +assertSame($expected_class, $block_plugin->getFormClass($operation)); + $this->assertSame($expected_class !== NULL, $block_plugin->hasFormClass($operation)); + } + + /** + * @return array + */ + public function providerGetFormClass() { + $block_plugin_without_forms = new TestClass([], 'block_plugin_without_forms', [ + 'provider' => 'block_test', + ]); + // A block plugin that has a form defined for the 'poke' operation. + $block_plugin_with_forms = new TestClass([], 'block_plugin_with_forms', [ + 'provider' => 'block_test', + 'forms' => [ + 'poke' => static::class, + ], + ]); + return [ + 'block plugin without forms, "configure" operation' => [$block_plugin_without_forms, 'configure', TestClass::class], + 'block plugin without forms, "tickle" operation' => [$block_plugin_without_forms, 'tickle', NULL], + 'block plugin withut forms, "poke" operation' => [$block_plugin_without_forms, 'poke', NULL], + 'block plugin with forms, "configure" operation' => [$block_plugin_with_forms, 'configure', TestClass::class], + 'block plugin with forms, "tickle" operation' => [$block_plugin_with_forms, 'tickle', NULL], + 'block plugin with forms, "poke" operation' => [$block_plugin_with_forms, 'poke', static::class], + ]; + } + +} + +class TestClass extends PluginBase implements PluginWithFormsInterface, PluginFormInterface { + use PluginWithFormsTrait; + + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + return []; + } + + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + } + + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + } + +}