diff --git a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php index 337e503..dee9f26 100644 --- a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php +++ b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php @@ -31,10 +31,23 @@ class DefaultFactory implements FactoryInterface { protected $discovery; /** + * Defines an interface each plugin should implement. + * + * @var string|null + */ + protected $interface; + + /** * Constructs a Drupal\Component\Plugin\Factory\DefaultFactory object. + * + * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery + * The plugin discovery. + * @param string|null $plugin_interface + * (optional) The interface each plugin should implement. */ - public function __construct(DiscoveryInterface $discovery) { + public function __construct(DiscoveryInterface $discovery, $plugin_interface = NULL) { $this->discovery = $discovery; + $this->interface = $plugin_interface; } /** @@ -42,7 +55,7 @@ public function __construct(DiscoveryInterface $discovery) { */ public function createInstance($plugin_id, array $configuration = array()) { $plugin_definition = $this->discovery->getDefinition($plugin_id); - $plugin_class = static::getPluginClass($plugin_id, $plugin_definition); + $plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface); return new $plugin_class($configuration, $plugin_id, $plugin_definition); } @@ -53,13 +66,18 @@ public function createInstance($plugin_id, array $configuration = array()) { * The id of a plugin. * @param mixed $plugin_definition * The plugin definition associated with the plugin ID. + * @param string $required_interface + * (optional) THe required plugin interface. * * @return string * The appropriate class name. * * @throws \Drupal\Component\Plugin\Exception\PluginException + * Thrown when there is no class specified, the class doesn't exist, or + * the class does not implement the specified required interface. + * */ - public static function getPluginClass($plugin_id, $plugin_definition = NULL) { + public static function getPluginClass($plugin_id, $plugin_definition = NULL, $required_interface = NULL) { if (empty($plugin_definition['class'])) { throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $plugin_id)); } @@ -70,6 +88,10 @@ public static function getPluginClass($plugin_id, $plugin_definition = NULL) { throw new PluginException(sprintf('Plugin (%s) instance class "%s" does not exist.', $plugin_id, $class)); } + if ($required_interface && !is_subclass_of($plugin_definition['class'], $required_interface)) { + throw new PluginException(sprintf('Plugin "%s" (%s) in %s should implement interface %s.', $plugin_id, $plugin_definition['class'], $plugin_definition['provider'], is_array($required_interface) ? implode(', ', $required_interface) : $required_interface)); + } + return $class; } } diff --git a/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php b/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php index 3fce8be..ae9dfe1 100644 --- a/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php +++ b/core/lib/Drupal/Component/Plugin/Factory/ReflectionFactory.php @@ -19,7 +19,7 @@ class ReflectionFactory extends DefaultFactory { */ public function createInstance($plugin_id, array $configuration = array()) { $plugin_definition = $this->discovery->getDefinition($plugin_id); - $plugin_class = static::getPluginClass($plugin_id, $plugin_definition); + $plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface); // Lets figure out of there's a constructor for this class and pull // arguments from the $options array if so to populate it. diff --git a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php index 58255b9..b3f451b 100644 --- a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php +++ b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php @@ -40,25 +40,6 @@ protected $mapper; /** - * Defines an interface each plugin should implement. - * - * @var string|null - */ - protected $interface; - - /** - * Constructs a new plugin manager. - * - * @param string|null $plugin_interface - * (optional) The interface each plugin should implement. - */ - public function __construct($plugin_interface = NULL) { - if ($plugin_interface) { - $this->interface = $plugin_interface; - } - } - - /** * {@inheritdoc} */ public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { @@ -76,7 +57,6 @@ public function getDefinitions() { * {@inheritdoc} */ public function createInstance($plugin_id, array $configuration = array()) { - $this->enforcePluginInterface($plugin_id); return $this->factory->createInstance($plugin_id, $configuration); } @@ -87,24 +67,4 @@ public function getInstance(array $options) { return $this->mapper->getInstance($options); } - /** - * Enforces that a plugin implements the required interface. - * - * @param string $plugin_id - * - * @throws \Drupal\Component\Plugin\Exception\PluginException - */ - protected function enforcePluginInterface($plugin_id) { - // If an interface is specified, enforce that the plugin implements it. - $plugin_definition = $this->getDefinition($plugin_id); - if ($this->interface && !is_subclass_of($plugin_definition['class'], $this->interface)) { - throw new PluginException(String::format('Plugin "@plugin_id" (@class) in @provider should implement interface @interface', array( - '@plugin_id' => $plugin_id, - '@class' => $plugin_definition['class'], - '@provider' => $plugin_definition['provider'], - '@interface' => is_array($this->interface) ? implode(', ', $this->interface) : $this->interface, - ))); - } - } - } diff --git a/core/lib/Drupal/Core/Archiver/ArchiverManager.php b/core/lib/Drupal/Core/Archiver/ArchiverManager.php index 9263bd3..a457a1f 100644 --- a/core/lib/Drupal/Core/Archiver/ArchiverManager.php +++ b/core/lib/Drupal/Core/Archiver/ArchiverManager.php @@ -33,7 +33,7 @@ class ArchiverManager extends DefaultPluginManager { * The module handler to invoke the alter hook with. */ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { - parent::__construct('Plugin/Archiver', $namespaces, $module_handler, 'Drupal\Core\Archiver\ArchiverInterface', 'Drupal\Core\Archiver\Annotation\Archiver'); + parent::__construct('Plugin/Archiver', $namespaces, $module_handler, 'Drupal\Core\Archiver\Annotation\Archiver'); $this->alterInfo('archiver_info'); $this->setCacheBackend($cache_backend, 'archiver_info_plugins'); } @@ -43,7 +43,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac */ public function createInstance($plugin_id, array $configuration = array()) { $plugin_definition = $this->getDefinition($plugin_id); - $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition); + $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition, 'Drupal\Core\Archiver\ArchiverInterface'); return new $plugin_class($configuration['filepath']); } diff --git a/core/lib/Drupal/Core/Field/WidgetFactory.php b/core/lib/Drupal/Core/Field/WidgetFactory.php index 9e9408f..db8c291 100644 --- a/core/lib/Drupal/Core/Field/WidgetFactory.php +++ b/core/lib/Drupal/Core/Field/WidgetFactory.php @@ -19,7 +19,7 @@ class WidgetFactory extends DefaultFactory { */ public function createInstance($plugin_id, array $configuration = array()) { $plugin_definition = $this->discovery->getDefinition($plugin_id); - $plugin_class = static::getPluginClass($plugin_id, $plugin_definition); + $plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface); return new $plugin_class($plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings']); } } diff --git a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php index 06bf61b..b99c11f 100644 --- a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php +++ b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php @@ -28,11 +28,6 @@ class ContextualLinkManager extends DefaultPluginManager implements ContextualLinkManagerInterface { /** - * {@inheritdoc} - */ - protected $interface = '\Drupal\Core\Menu\ContextualLinkInterface'; - - /** * Provides default values for a contextual link definition. * * @var array @@ -110,7 +105,7 @@ class ContextualLinkManager extends DefaultPluginManager implements ContextualLi public function __construct(ControllerResolverInterface $controller_resolver, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account, RequestStack $request_stack) { $this->discovery = new YamlDiscovery('links.contextual', $module_handler->getModuleDirectories()); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); - $this->factory = new ContainerFactory($this); + $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\ContextualLinkInterface'); $this->controllerResolver = $controller_resolver; $this->accessManager = $access_manager; diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php index 4406219..1033d79 100644 --- a/core/lib/Drupal/Core/Menu/LocalActionManager.php +++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php @@ -26,11 +26,6 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionManagerInterface { /** - * {@inheritdoc} - */ - protected $interface = '\Drupal\Core\Menu\LocalActionInterface'; - - /** * Provides some default values for all local action plugins. * * @var array @@ -121,7 +116,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re // discovery. $this->discovery = new YamlDiscovery('links.action', $module_handler->getModuleDirectories()); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); - $this->factory = new ContainerFactory($this); + $this->factory = new ContainerFactory($this, 'Drupal\Core\Menu\LocalActionInterface'); $this->controllerResolver = $controller_resolver; $this->requestStack = $request_stack; $this->routeProvider = $route_provider; diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php index 1773090..862050c 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php @@ -31,11 +31,6 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI /** * {@inheritdoc} */ - protected $interface = '\Drupal\Core\Menu\LocalTaskInterface'; - - /** - * {@inheritdoc} - */ protected $defaults = array( // (required) The name of the route this task links to. 'route_name' => '', @@ -131,7 +126,7 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) { $this->discovery = new YamlDiscovery('links.task', $module_handler->getModuleDirectories()); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); - $this->factory = new ContainerFactory($this); + $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\LocalTaskInterface'); $this->controllerResolver = $controller_resolver; $this->requestStack = $request_stack; $this->routeProvider = $route_provider; diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 5f2dfa3..a2d4cf2 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -97,11 +97,10 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt * Defaults to 'Drupal\Component\Annotation\Plugin'. */ public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') { - parent::__construct($plugin_interface); $this->subdir = $subdir; $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $plugin_definition_annotation_name); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); - $this->factory = new ContainerFactory($this); + $this->factory = new ContainerFactory($this, $plugin_interface); $this->moduleHandler = $module_handler; } diff --git a/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php b/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php index 702e640..16191f8 100644 --- a/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php +++ b/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php @@ -18,7 +18,7 @@ class ContainerFactory extends DefaultFactory { */ public function createInstance($plugin_id, array $configuration = array()) { $plugin_definition = $this->discovery->getDefinition($plugin_id); - $plugin_class = static::getPluginClass($plugin_id, $plugin_definition); + $plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface); // If the plugin provides a factory method, pass the container to it. if (is_subclass_of($plugin_class, 'Drupal\Core\Plugin\ContainerFactoryPluginInterface')) { diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php index 9dee11a..6c99ce1 100644 --- a/core/modules/config_translation/src/ConfigMapperManager.php +++ b/core/modules/config_translation/src/ConfigMapperManager.php @@ -29,11 +29,6 @@ class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperManagerInterface { /** - * {@inheritdoc} - */ - protected $interface = '\Drupal\config_translation\ConfigMapperInterface'; - - /** * The typed config manager. * * @var \Drupal\Core\Config\TypedConfigManagerInterface @@ -95,7 +90,7 @@ public function __construct(CacheBackendInterface $cache_backend, LanguageManage $this->discovery = new InfoHookDecorator($this->discovery, 'config_translation_info'); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); - $this->factory = new ContainerFactory($this); + $this->factory = new ContainerFactory($this, '\Drupal\config_translation\ConfigMapperInterface'); // Let others alter definitions with hook_config_translation_info_alter(). $this->moduleHandler = $module_handler; diff --git a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php index c40dde0..b4e17a1 100644 --- a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php +++ b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php @@ -31,17 +31,12 @@ class SelectionPluginManager extends DefaultPluginManager { /** * {@inheritdoc} */ - protected $interface = '\Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface'; - - /** - * {@inheritdoc} - */ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { $this->discovery = new AnnotatedClassDiscovery('Plugin/entity_reference/selection', $namespaces, 'Drupal\entity_reference\Annotation\EntityReferenceSelection'); // We're not using the parent constructor because we use a different factory // method and don't need the derivative discovery decorator. - $this->factory = new ReflectionFactory($this); + $this->factory = new ReflectionFactory($this, '\Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface'); $this->moduleHandler = $module_handler; $this->alterInfo('entity_reference_selection'); diff --git a/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php b/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php index 1a1f881..8af36d6 100644 --- a/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php +++ b/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php @@ -7,6 +7,9 @@ namespace Drupal\migrate_drupal\Plugin; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Plugin\Factory\ContainerFactory; use Drupal\migrate\Plugin\MigratePluginManager as BaseMigratePluginManager; /** @@ -21,6 +24,11 @@ class MigratePluginManager extends BaseMigratePluginManager { /** * {@inheritdoc} */ - protected $interface = 'Drupal\migrate_drupal\Plugin\MigrateLoadInterface'; + public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\Component\Annotation\PluginID') { + parent::__construct($type, $namespaces, $cache_backend, $module_handler, $annotation); + + $this->factory = new ContainerFactory($this, 'Drupal\migrate_drupal\Plugin\MigrateLoadInterface'); + } + } diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php index 737ad91..bda80fa 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php @@ -29,9 +29,8 @@ public function __construct(ModuleHandlerInterface $module_handler) { // discovery implementation, but StaticDiscovery lets us add some simple // mock plugins for unit testing. $this->discovery = new StaticDiscovery(); - $this->factory = new DefaultFactory($this); + $this->factory = new DefaultFactory($this, 'Drupal\Component\Plugin\PluginInspectionInterface'); $this->moduleHandler = $module_handler; - $this->interface = 'Drupal\Component\Plugin\PluginInspectionInterface'; // Specify default values. $this->defaults = array(