3 namespace Drupal\Core\Plugin\Discovery;
5 use Drupal\Component\Annotation\AnnotationInterface;
6 use Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery;
7 use Drupal\Component\Utility\Unicode;
10 * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
12 class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
15 * A suffix to append to each PSR-4 directory associated with a base
16 * namespace, to form the directories where plugins are found.
20 protected $directorySuffix = '';
23 * A suffix to append to each base namespace, to obtain the namespaces where
28 protected $namespaceSuffix = '';
31 * A list of base namespaces with their PSR-4 directories.
35 protected $rootNamespacesIterator;
38 * Constructs an AnnotatedClassDiscovery object.
40 * @param string $subdir
41 * Either the plugin's subdirectory, for example 'Plugin/views/filter', or
42 * empty string if plugins are located at the top level of the namespace.
43 * @param \Traversable $root_namespaces
44 * An object that implements \Traversable which contains the root paths
45 * keyed by the corresponding namespace to look for plugin implementations.
46 * If $subdir is not an empty string, it will be appended to each namespace.
47 * @param string $plugin_definition_annotation_name
48 * (optional) The name of the annotation that contains the plugin definition.
49 * Defaults to 'Drupal\Component\Annotation\Plugin'.
50 * @param string[] $annotation_namespaces
51 * (optional) Additional namespaces to scan for annotation definitions.
53 public function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) {
55 // Prepend a directory separator to $subdir,
56 // if it does not already have one.
57 if ('/' !== $subdir[0]) {
58 $subdir = '/' . $subdir;
60 $this->directorySuffix = $subdir;
61 $this->namespaceSuffix = str_replace('/', '\\', $subdir);
63 $this->rootNamespacesIterator = $root_namespaces;
64 $plugin_namespaces = [];
65 parent::__construct($plugin_namespaces, $plugin_definition_annotation_name, $annotation_namespaces);
71 protected function getAnnotationReader() {
72 if (!isset($this->annotationReader)) {
73 $reader = parent::getAnnotationReader();
75 // Add the Core annotation classes like @Translation.
76 $reader->addNamespace('Drupal\Core\Annotation');
77 $this->annotationReader = $reader;
79 return $this->annotationReader;
85 protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) {
86 parent::prepareAnnotationDefinition($annotation, $class);
88 if (!$annotation->getProvider()) {
89 $annotation->setProvider($this->getProviderFromNamespace($class));
94 * Extracts the provider name from a Drupal namespace.
96 * @param string $namespace
97 * The namespace to extract the provider from.
100 * The matching provider name, or NULL otherwise.
102 protected function getProviderFromNamespace($namespace) {
103 preg_match('|^Drupal\\\\(?<provider>[\w]+)\\\\|', $namespace, $matches);
105 if (isset($matches['provider'])) {
106 return Unicode::strtolower($matches['provider']);
115 protected function getPluginNamespaces() {
116 $plugin_namespaces = [];
117 if ($this->namespaceSuffix) {
118 foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
119 // Append the namespace suffix to the base namespace, to obtain the
120 // plugin namespace; for example, 'Drupal\Views' may become
121 // 'Drupal\Views\Plugin\Block'.
122 $namespace .= $this->namespaceSuffix;
123 foreach ((array) $dirs as $dir) {
124 // Append the directory suffix to the PSR-4 base directory, to obtain
125 // the directory where plugins are found. For example,
126 // DRUPAL_ROOT . '/core/modules/views/src' may become
127 // DRUPAL_ROOT . '/core/modules/views/src/Plugin/Block'.
128 $plugin_namespaces[$namespace][] = $dir . $this->directorySuffix;
133 // Both the namespace suffix and the directory suffix are empty,
134 // so the plugin namespaces and directories are the same as the base
136 foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
137 $plugin_namespaces[$namespace] = (array) $dirs;
141 return $plugin_namespaces;