Commit db8849dd authored by xjm's avatar xjm

Revert "Issue #2773197 by jalpesh, tstoeckler:...

Revert "Issue #2773197 by jalpesh, tstoeckler: DefaultHtmlRouteProviderTest::testGetCollectionRoute() has wrong @covers"

This reverts commit a470bc0c.
parent a470bc0c
......@@ -577,9 +577,6 @@ services:
entity.autocomplete_matcher:
class: Drupal\Core\Entity\EntityAutocompleteMatcher
arguments: ['@plugin.manager.entity_reference_selection']
plugin_form.factory:
class: Drupal\Core\Plugin\PluginFormFactory
arguments: ['@class_resolver']
plugin.manager.entity_reference_selection:
class: Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager
parent: default_plugin_manager
......
<?php
namespace Drupal\Component\Plugin;
/**
* Provides an interface for objects that depend on a plugin.
*/
interface PluginAwareInterface {
/**
* Sets the plugin for this object.
*
* @param \Drupal\Component\Plugin\PluginInspectionInterface $plugin
* The plugin.
*/
public function setPlugin(PluginInspectionInterface $plugin);
}
......@@ -10,7 +10,6 @@
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Plugin\PluginWithFormsInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Component\Transliteration\TransliterationInterface;
......@@ -23,7 +22,7 @@
*
* @ingroup block_api
*/
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface {
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface {
use ContextAwarePluginAssignmentTrait;
......@@ -272,20 +271,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]);
}
}
......@@ -239,20 +239,9 @@ public function useCaches($use_caches = FALSE) {
* method.
*/
public function processDefinition(&$definition, $plugin_id) {
// Only arrays can be operated on.
if (!is_array($definition)) {
return;
}
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'];
}
}
/**
......
<?php
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\PluginAwareInterface;
use Drupal\Component\Plugin\PluginInspectionInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides a base class for plugin forms.
*
* Classes extending this can be in any namespace, but are commonly placed in
* the 'PluginForm' namespace, such as \Drupal\module_name\PluginForm\ClassName.
*/
abstract class PluginFormBase implements PluginFormInterface, PluginAwareInterface {
/**
* The plugin this form is for.
*
* @var \Drupal\Component\Plugin\PluginInspectionInterface
*/
protected $plugin;
/**
* {@inheritdoc}
*/
public function setPlugin(PluginInspectionInterface $plugin) {
$this->plugin = $plugin;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
// Validation is optional.
}
}
<?php
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\PluginAwareInterface;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
/**
* Provides form discovery capabilities for plugins.
*/
class PluginFormFactory implements PluginFormFactoryInterface {
/**
* The class resolver.
*
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
*/
protected $classResolver;
/**
* PluginFormFactory constructor.
*
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver.
*/
public function __construct(ClassResolverInterface $class_resolver) {
$this->classResolver = $class_resolver;
}
/**
* {@inheritdoc}
*/
public function createInstance(PluginWithFormsInterface $plugin, $operation, $fallback_operation = NULL) {
if (!$plugin->hasFormClass($operation)) {
// Use the default form class if no form is specified for this operation.
if ($fallback_operation && $plugin->hasFormClass($fallback_operation)) {
$operation = $fallback_operation;
}
else {
throw new InvalidPluginDefinitionException($plugin->getPluginId(), sprintf('The "%s" plugin did not specify a "%s" form class', $plugin->getPluginId(), $operation));
}
}
$form_class = $plugin->getFormClass($operation);
// If the form specified is the plugin itself, use it directly.
if (ltrim(get_class($plugin), '\\') === ltrim($form_class, '\\')) {
$form_object = $plugin;
}
else {
$form_object = $this->classResolver->getInstanceFromDefinition($form_class);
}
// Ensure the resulting object is a plugin form.
if (!$form_object instanceof PluginFormInterface) {
throw new InvalidPluginDefinitionException($plugin->getPluginId(), sprintf('The "%s" plugin did not specify a valid "%s" form class, must implement \Drupal\Core\Plugin\PluginFormInterface', $plugin->getPluginId(), $operation));
}
if ($form_object instanceof PluginAwareInterface) {
$form_object->setPlugin($plugin);
}
return $form_object;
}
}
<?php
namespace Drupal\Core\Plugin;
/**
* Provides an interface for retrieving form objects for plugins.
*
* This allows a plugin to define multiple forms, in addition to the plugin
* itself providing a form. All forms, decoupled or self-contained, must
* implement \Drupal\Core\Plugin\PluginFormInterface. Decoupled forms can
* implement \Drupal\Component\Plugin\PluginAwareInterface in order to gain
* access to the plugin.
*/
interface PluginFormFactoryInterface {
/**
* Creates a new form instance.
*
* @param \Drupal\Core\Plugin\PluginWithFormsInterface $plugin
* The plugin the form is for.
* @param string $operation
* The name of the operation to use, e.g., 'add' or 'edit'.
* @param string $fallback_operation
* (optional) The name of the fallback operation to use.
*
* @return \Drupal\Core\Plugin\PluginFormInterface
* A plugin form instance.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
public function createInstance(PluginWithFormsInterface $plugin, $operation, $fallback_operation = NULL);
}
......@@ -7,10 +7,6 @@
/**
* Provides an interface for an embeddable plugin form.
*
* Plugins can implement this form directly, or a standalone class can be used.
* Decoupled forms can implement \Drupal\Component\Plugin\PluginAwareInterface
* in order to gain access to the plugin.
*
* @ingroup plugin_api
*/
interface PluginFormInterface {
......
<?php
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\PluginInspectionInterface;
/**
* Provides an interface for plugins which have forms.
*
* Plugin forms are embeddable forms referenced by the plugin annotation.
* Used by plugin types which have a larger number of plugin-specific forms.
*/
interface PluginWithFormsInterface extends PluginInspectionInterface {
/**
* Gets the form class for the given operation.
*
* @param string $operation
* The name of the operation.
*
* @return string|null
* The form class if defined, NULL otherwise.
*/
public function getFormClass($operation);
/**
* Gets whether the plugin has a form class for the given operation.
*
* @param string $operation
* The name of the operation.
*
* @return bool
* TRUE if the plugin has a form class for the given operation.
*/
public function hasFormClass($operation);
}
......@@ -3,8 +3,6 @@
namespace Drupal\block;
use Drupal\Component\Utility\Html;
use Drupal\Core\Plugin\PluginFormFactoryInterface;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Executable\ExecutableManagerInterface;
......@@ -70,13 +68,6 @@ class BlockForm extends EntityForm {
*/
protected $contextRepository;
/**
* The plugin form manager.
*
* @var \Drupal\Core\Plugin\PluginFormFactoryInterface
*/
protected $pluginFormFactory;
/**
* Constructs a BlockForm object.
*
......@@ -90,16 +81,13 @@ class BlockForm extends EntityForm {
* The language manager.
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
* The theme handler.
* @param \Drupal\Core\Plugin\PluginFormFactoryInterface $plugin_form_manager
* The plugin form manager.
*/
public function __construct(EntityManagerInterface $entity_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler, PluginFormFactoryInterface $plugin_form_manager) {
public function __construct(EntityManagerInterface $entity_manager, ExecutableManagerInterface $manager, ContextRepositoryInterface $context_repository, LanguageManagerInterface $language, ThemeHandlerInterface $theme_handler) {
$this->storage = $entity_manager->getStorage('block');
$this->manager = $manager;
$this->contextRepository = $context_repository;
$this->language = $language;
$this->themeHandler = $theme_handler;
$this->pluginFormFactory = $plugin_form_manager;
}
/**
......@@ -111,8 +99,7 @@ public static function create(ContainerInterface $container) {
$container->get('plugin.manager.condition'),
$container->get('context.repository'),
$container->get('language_manager'),
$container->get('theme_handler'),
$container->get('plugin_form.factory')
$container->get('theme_handler')
);
}
......@@ -133,7 +120,7 @@ public function form(array $form, FormStateInterface $form_state) {
$form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts());
$form['#tree'] = TRUE;
$form['settings'] = $this->getPluginForm($entity->getPlugin())->buildConfigurationForm(array(), $form_state);
$form['settings'] = $entity->getPlugin()->buildConfigurationForm(array(), $form_state);
$form['visibility'] = $this->buildVisibilityInterface([], $form_state);
// If creating a new block, calculate a safe default machine name.
......@@ -295,7 +282,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
// settings form element, so just pass that to the block for validation.
$settings = (new FormState())->setValues($form_state->getValue('settings'));
// Call the plugin validate handler.
$this->getPluginForm($this->entity->getPlugin())->validateConfigurationForm($form, $settings);
$this->entity->getPlugin()->validateConfigurationForm($form, $settings);
// Update the original form values.
$form_state->setValue('settings', $settings->getValues());
$this->validateVisibility($form, $form_state);
......@@ -342,8 +329,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
$settings = (new FormState())->setValues($form_state->getValue('settings'));
// Call the plugin submit handler.
$entity->getPlugin()->submitConfigurationForm($form, $settings);
$block = $entity->getPlugin();
$this->getPluginForm($block)->submitConfigurationForm($form, $settings);
// If this block is context-aware, set the context mapping.
if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) {
$context_mapping = $settings->getValue('context_mapping', []);
......@@ -415,17 +402,4 @@ public function getUniqueMachineName(BlockInterface $block) {
return $machine_default;
}
/**
* Retrieves the plugin form for a given block and operation.
*
* @param \Drupal\Core\Block\BlockPluginInterface $block
* The block plugin.
*
* @return \Drupal\Core\Plugin\PluginFormInterface
* The plugin form for the block.
*/
protected function getPluginForm(BlockPluginInterface $block) {
return $this->pluginFormFactory->createInstance($block, 'configure');
}
}
<?php
namespace Drupal\block_test\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides a block with multiple forms.
*
* @Block(
* id = "test_multiple_forms_block",
* forms = {
* "secondary" = "\Drupal\block_test\PluginForm\EmptyBlockForm"
* },
* admin_label = @Translation("Multiple forms test block")
* )
*/
class TestMultipleFormsBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
return [];
}
}
<?php
namespace Drupal\block_test\PluginForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormBase;
/**
* Provides a form for a block that is empty.
*/
class EmptyBlockForm extends PluginFormBase {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
// Intentionally empty.
}
}
......@@ -3,7 +3,6 @@
namespace Drupal\Tests\block\Unit;
use Drupal\block\BlockForm;
use Drupal\Core\Plugin\PluginFormFactoryInterface;
use Drupal\Tests\UnitTestCase;
/**
......@@ -55,13 +54,6 @@ class BlockFormTest extends UnitTestCase {
*/
protected $contextRepository;
/**
* The plugin form manager.
*
* @var \Drupal\Core\Plugin\PluginFormFactoryInterface|\Prophecy\Prophecy\ProphecyInterface
*/
protected $pluginFormFactory;
/**
* {@inheritdoc}
*/
......@@ -79,7 +71,6 @@ protected function setUp() {
->method('getStorage')
->will($this->returnValue($this->storage));
$this->pluginFormFactory = $this->prophesize(PluginFormFactoryInterface::class);
}
/**
......@@ -108,7 +99,7 @@ public function testGetUniqueMachineName() {
->method('getQuery')
->will($this->returnValue($query));
$block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler, $this->pluginFormFactory->reveal());
$block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler);
// Ensure that the block with just one other instance gets the next available
// name suggestion.
......
<?php
namespace Drupal\KernelTests\Core\Block;
use Drupal\block_test\PluginForm\EmptyBlockForm;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests that blocks can have multiple forms.
*
* @group block
*/
class MultipleBlockFormTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'block', 'block_test'];
/**
* Tests that blocks can have multiple forms.
*/
public function testMultipleForms() {
$configuration = ['label' => 'A very cool block'];
$block = \Drupal::service('plugin.manager.block')->createInstance('test_multiple_forms_block', $configuration);
$form_object1 = \Drupal::service('plugin_form.factory')->createInstance($block, 'configure');
$form_object2 = \Drupal::service('plugin_form.factory')->createInstance($block, 'secondary');
// Assert that the block itself is used for the default form.
$this->assertSame($block, $form_object1);
// Ensure that EmptyBlockForm is used and the plugin is set.
$this->assertInstanceOf(EmptyBlockForm::class, $form_object2);
$this->assertAttributeEquals($block, 'plugin', $form_object2);
}
}
......@@ -3,8 +3,6 @@
namespace Drupal\Tests\Core\Plugin;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Tests\UnitTestCase;
/**
......@@ -340,98 +338,4 @@ public function testGetCacheMaxAge() {
$this->assertInternalType('int', $cache_max_age);
}
/**
* @covers ::processDefinition
* @dataProvider providerTestProcessDefinition
*/
public function testProcessDefinition($definition, $expected) {
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
$plugin_manager = new TestPluginManagerWithDefaults($this->namespaces, $this->expectedDefinitions, $module_handler->reveal(), NULL);
$plugin_manager->processDefinition($definition, 'the_plugin_id');
$this->assertEquals($expected, $definition);
}
public function providerTestProcessDefinition() {
$data = [];
$data['merge'][] = [
'foo' => [
'bar' => [
'asdf',
],
],
];
$data['merge'][] = [
'foo' => [
'bar' => [
'baz',
'asdf',
],
],
];
$object_definition = (object) [
'foo' => [
'bar' => [
'asdf',
],
],
];
$data['object_definition'] = [$object_definition, clone $object_definition];
$data['no_form'][] = ['class' => TestPluginForm::class];
$data['no_form'][] = [
'class' => TestPluginForm::class,
'forms' => ['configure' => TestPluginForm::class],
'foo' => ['bar' => ['baz']],
];
$data['default_form'][] = ['class' => TestPluginForm::class, 'forms' => ['configure' => 'stdClass']];
$data['default_form'][] = [
'class' => TestPluginForm::class,
'forms' => ['configure' => 'stdClass'],
'foo' => ['bar' => ['baz']],
];
return $data;
}
}
class TestPluginManagerWithDefaults extends TestPluginManager {
/**
* {@inheritdoc}
*/
protected $defaults = [
'foo' => [
'bar' => [
'baz',
],
],
];
}
class TestPluginForm implements PluginFormInterface {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
return [];
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
}
}
<?php
namespace Drupal\Tests\Core\Plugin;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\PluginAwareInterface;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Plugin\PluginFormFactory;
use Drupal\Core\Plugin\PluginWithFormsInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\Core\Plugin\PluginFormFactory
* @group Plugin
*/
class PluginFormFactoryTest extends UnitTestCase {
/**
* The class resolver.
*
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface|\Prophecy\Prophecy\ProphecyInterface
*/
protected $classResolver;
/**
* The manager being tested.
*
* @var \Drupal\Core\Plugin\PluginFormFactory
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->classResolver = $this->prophesize(ClassResolverInterface::class);
$this->manager = new PluginFormFactory($this->classResolver->reveal());
}
/**
* @covers ::createInstance
*/
public function testCreateInstance() {
$plugin_form = $this->prophesize(PluginFormInterface::class);
$expected = $plugin_form->reveal();
$this->classResolver->getInstanceFromDefinition(get_class($expected))->willReturn($expected);
$plugin = $this->prophesize(PluginWithFormsInterface::class);
$plugin->hasFormClass('standard_class')->willReturn(TRUE);
$plugin->getFormClass('standard_class')->willReturn(get_class($expected));
$form_object = $this->manager->createInstance($plugin->reveal(), 'standard_class');
$this->assertSame($expected, $form_object);
}
/**
* @covers ::createInstance
*/
public function testCreateInstanceUsingPlugin() {
$this->classResolver->getInstanceFromDefinition(Argument::cetera())->shouldNotBeCalled();
$plugin = $this->prophesize(PluginWithFormsInterface::class)->willImplement(PluginFormInterface::class);
$plugin->hasFormClass('configure')->willReturn(TRUE);
$plugin->getFormClass('configure')->willReturn(get_class($plugin->reveal()));
$form_object = $this->manager->createInstance($plugin->reveal(), 'configure');
$this->assertSame($plugin->reveal(), $form_object);
}
/**
* @covers ::createInstance
*/
public function testCreateInstanceUsingPluginWithSlashes() {
$this->classResolver->getInstanceFromDefinition(Argument::cetera())->shouldNotBeCalled();
$plugin = $this->prophesize(PluginWithFormsInterface::class)->willImplement(PluginFormInterface::class);
$plugin->hasFormClass('configure')->willReturn(TRUE);
$plugin->getFormClass('configure')->willReturn('\\' . get_class($plugin->reveal()));
$form_object = $this->manager->createInstance($plugin->reveal(), 'configure');
$this->assertSame($plugin->reveal(), $form_object);
}
/**
* @covers ::createInstance
*/
public function testCreateInstanceDefaultFallback() {
$this->classResolver->getInstanceFromDefinition(Argument::cetera())->shouldNotBeCalled();
$plugin = $this->prophesize(PluginWithFormsInterface::class)->willImplement(PluginFormInterface::class);
$plugin->hasFormClass('missing')->willReturn(FALSE);
$plugin->hasFormClass('fallback')->willReturn(TRUE);
$plugin->getFormClass('fallback')->willReturn(get_class($plugin->reveal()));