diff --git a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php index edfce73..11ed449 100644 --- a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -47,6 +47,13 @@ class AnnotatedClassDiscovery implements DiscoveryInterface { protected $annotationReader; /** + * Additional namespaces to be scanned for annotation classes. + * + * @var string[] + */ + protected $annotationNamespaces = []; + + /** * Constructs a new instance. * * @param string[] $plugin_namespaces @@ -55,10 +62,13 @@ class AnnotatedClassDiscovery implements DiscoveryInterface { * @param string $plugin_definition_annotation_name * (optional) The name of the annotation that contains the plugin definition. * Defaults to 'Drupal\Component\Annotation\Plugin'. + * @param string[] $annotation_namespaces + * (optional) Additional namespaces to be scanned for annotation classes. */ - function __construct($plugin_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') { + function __construct($plugin_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) { $this->pluginNamespaces = $plugin_namespaces; $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name; + $this->annotationNamespaces = $annotation_namespaces; } /** @@ -74,6 +84,11 @@ protected function getAnnotationReader() { // Add the namespaces from the main plugin annotation, like @EntityType. $namespace = substr($this->pluginDefinitionAnnotationName, 0, strrpos($this->pluginDefinitionAnnotationName, '\\')); $this->annotationReader->addNamespace($namespace); + + // Register additional namespaces to be scanned for annotations. + foreach ($this->annotationNamespaces as $namespace) { + $this->annotationReader->addNamespace($namespace); + } } return $this->annotationReader; } diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 26b7161..0232fbe 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -42,7 +42,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt * * @var array */ - protected $cacheTags = array(); + protected $cacheTags = []; /** * Name of the alter hook if one should be invoked. @@ -73,7 +73,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt * * @var array */ - protected $defaults = array(); + protected $defaults = []; /** * The name of the annotation that contains the plugin definition. @@ -98,6 +98,14 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt protected $namespaces; /** + * Additional namespaces the annotation discovery mechanism should scan for + * annotation definitions. + * + * @var string[] + */ + protected $annotationNamespaces = []; + + /** * Creates the discovery object. * * @param string|bool $subdir @@ -112,13 +120,16 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt * @param string $plugin_definition_annotation_name * (optional) The name of the annotation that contains the plugin definition. * Defaults to 'Drupal\Component\Annotation\Plugin'. + * @param string[] $annotation_namespaces + * (optional) Additional namespaces to scan for annotation definitions. */ - public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') { + public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) { $this->subdir = $subdir; $this->namespaces = $namespaces; $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name; $this->pluginInterface = $plugin_interface; $this->moduleHandler = $module_handler; + $this->annotationNamespaces = $annotation_namespaces; } /** @@ -188,6 +199,18 @@ public function clearCachedDefinitions() { } /** + * Adds a namespace to be scanned for annotation definitions. + * + * @param string $namespace + * The namespace to add. + */ + public function addAnnotationNamespace($namespace) { + if (!in_array($namespace, $this->annotationNamespaces)) { + array_push($this->annotationNamespaces, $namespace); + } + } + + /** * Returns the cached plugin definitions of the decorated discovery class. * * @return array|null @@ -242,7 +265,7 @@ public function processDefinition(&$definition, $plugin_id) { */ protected function getDiscovery() { if (!$this->discovery) { - $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName); + $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->annotationNamespaces); $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery); } return $this->discovery; diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php index 8cb4888..d8dc436 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -52,8 +52,10 @@ class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery { * @param string $plugin_definition_annotation_name * (optional) The name of the annotation that contains the plugin definition. * Defaults to 'Drupal\Component\Annotation\Plugin'. + * @param string[] $annotation_namespaces + * (optional) Additional namespaces to scan for annotation definitions. */ - function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') { + function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = array()) { if ($subdir) { // Prepend a directory separator to $subdir, // if it does not already have one. @@ -65,7 +67,7 @@ function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_ } $this->rootNamespacesIterator = $root_namespaces; $plugin_namespaces = array(); - parent::__construct($plugin_namespaces, $plugin_definition_annotation_name); + parent::__construct($plugin_namespaces, $plugin_definition_annotation_name, $annotation_namespaces); } /** diff --git a/core/modules/system/src/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php b/core/modules/system/src/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php index 6cca8f5..76f5aeb 100644 --- a/core/modules/system/src/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php +++ b/core/modules/system/src/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php @@ -57,12 +57,21 @@ protected function setUp() { 'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Orange', 'provider' => 'plugin_test', ), + 'big_apple' => array( + 'id' => 'big_apple', + 'label' => 'Big Apple', + 'color' => 'green', + 'class' => 'Drupal\plugin_test_extra\Plugin\plugin_test\fruit\BigApple', + 'provider' => 'plugin_test_extra', + ), ); $base_directory = \Drupal::root() . '/core/modules/system/tests/modules/plugin_test/src'; - $namespaces = new \ArrayObject(array('Drupal\plugin_test' => $base_directory)); + $base_directory2 = \Drupal::root() . '/core/modules/system/tests/modules/plugin_test_extra/src'; + $namespaces = new \ArrayObject(array('Drupal\plugin_test' => $base_directory, 'Drupal\plugin_test_extra' => $base_directory2)); - $this->discovery = new AnnotatedClassDiscovery('Plugin/plugin_test/fruit', $namespaces); + $annotation_namespaces = ['Drupal\plugin_test\Plugin\Annotation', 'Drupal\plugin_test_extra\Plugin\Annotation']; + $this->discovery = new AnnotatedClassDiscovery('Plugin/plugin_test/fruit', $namespaces, 'Drupal\Component\Annotation\Plugin', $annotation_namespaces); $this->emptyDiscovery = new AnnotatedClassDiscovery('Plugin/non_existing_module/non_existing_plugin_type', $namespaces); } diff --git a/core/modules/system/tests/modules/plugin_test_extra/plugin_test_extra.info.yml b/core/modules/system/tests/modules/plugin_test_extra/plugin_test_extra.info.yml new file mode 100644 index 0000000..c8bf6cb --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test_extra/plugin_test_extra.info.yml @@ -0,0 +1,6 @@ +name: 'Plugin Test Extra' +type: module +description: 'Test that plugins can provide plugins and provide namespace discovery for plugin test implementations.' +package: Testing +version: VERSION +core: 8.x diff --git a/core/modules/system/tests/modules/plugin_test_extra/src/Plugin/Annotation/PluginExampleExtended.php b/core/modules/system/tests/modules/plugin_test_extra/src/Plugin/Annotation/PluginExampleExtended.php new file mode 100644 index 0000000..0cada97 --- /dev/null +++ b/core/modules/system/tests/modules/plugin_test_extra/src/Plugin/Annotation/PluginExampleExtended.php @@ -0,0 +1,19 @@ +