Pull merge.
[yaffs-website] / web / core / lib / Drupal / Core / Plugin / Discovery / AnnotatedClassDiscovery.php
1 <?php
2
3 namespace Drupal\Core\Plugin\Discovery;
4
5 use Drupal\Component\Annotation\AnnotationInterface;
6 use Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery;
7
8 /**
9  * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
10  */
11 class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
12
13   /**
14    * A suffix to append to each PSR-4 directory associated with a base
15    * namespace, to form the directories where plugins are found.
16    *
17    * @var string
18    */
19   protected $directorySuffix = '';
20
21   /**
22    * A suffix to append to each base namespace, to obtain the namespaces where
23    * plugins are found.
24    *
25    * @var string
26    */
27   protected $namespaceSuffix = '';
28
29   /**
30    * A list of base namespaces with their PSR-4 directories.
31    *
32    * @var \Traversable
33    */
34   protected $rootNamespacesIterator;
35
36   /**
37    * Constructs an AnnotatedClassDiscovery object.
38    *
39    * @param string $subdir
40    *   Either the plugin's subdirectory, for example 'Plugin/views/filter', or
41    *   empty string if plugins are located at the top level of the namespace.
42    * @param \Traversable $root_namespaces
43    *   An object that implements \Traversable which contains the root paths
44    *   keyed by the corresponding namespace to look for plugin implementations.
45    *   If $subdir is not an empty string, it will be appended to each namespace.
46    * @param string $plugin_definition_annotation_name
47    *   (optional) The name of the annotation that contains the plugin definition.
48    *   Defaults to 'Drupal\Component\Annotation\Plugin'.
49    * @param string[] $annotation_namespaces
50    *   (optional) Additional namespaces to scan for annotation definitions.
51    */
52   public function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) {
53     if ($subdir) {
54       // Prepend a directory separator to $subdir,
55       // if it does not already have one.
56       if ('/' !== $subdir[0]) {
57         $subdir = '/' . $subdir;
58       }
59       $this->directorySuffix = $subdir;
60       $this->namespaceSuffix = str_replace('/', '\\', $subdir);
61     }
62     $this->rootNamespacesIterator = $root_namespaces;
63     $plugin_namespaces = [];
64     parent::__construct($plugin_namespaces, $plugin_definition_annotation_name, $annotation_namespaces);
65   }
66
67   /**
68    * {@inheritdoc}
69    */
70   protected function getAnnotationReader() {
71     if (!isset($this->annotationReader)) {
72       $reader = parent::getAnnotationReader();
73
74       // Add the Core annotation classes like @Translation.
75       $reader->addNamespace('Drupal\Core\Annotation');
76       $this->annotationReader = $reader;
77     }
78     return $this->annotationReader;
79   }
80
81   /**
82    * {@inheritdoc}
83    */
84   protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) {
85     parent::prepareAnnotationDefinition($annotation, $class);
86
87     if (!$annotation->getProvider()) {
88       $annotation->setProvider($this->getProviderFromNamespace($class));
89     }
90   }
91
92   /**
93    * Extracts the provider name from a Drupal namespace.
94    *
95    * @param string $namespace
96    *   The namespace to extract the provider from.
97    *
98    * @return string|null
99    *   The matching provider name, or NULL otherwise.
100    */
101   protected function getProviderFromNamespace($namespace) {
102     preg_match('|^Drupal\\\\(?<provider>[\w]+)\\\\|', $namespace, $matches);
103
104     if (isset($matches['provider'])) {
105       return mb_strtolower($matches['provider']);
106     }
107
108     return NULL;
109   }
110
111   /**
112    * {@inheritdoc}
113    */
114   protected function getPluginNamespaces() {
115     $plugin_namespaces = [];
116     if ($this->namespaceSuffix) {
117       foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
118         // Append the namespace suffix to the base namespace, to obtain the
119         // plugin namespace; for example, 'Drupal\Views' may become
120         // 'Drupal\Views\Plugin\Block'.
121         $namespace .= $this->namespaceSuffix;
122         foreach ((array) $dirs as $dir) {
123           // Append the directory suffix to the PSR-4 base directory, to obtain
124           // the directory where plugins are found. For example,
125           // DRUPAL_ROOT . '/core/modules/views/src' may become
126           // DRUPAL_ROOT . '/core/modules/views/src/Plugin/Block'.
127           $plugin_namespaces[$namespace][] = $dir . $this->directorySuffix;
128         }
129       }
130     }
131     else {
132       // Both the namespace suffix and the directory suffix are empty,
133       // so the plugin namespaces and directories are the same as the base
134       // directories.
135       foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
136         $plugin_namespaces[$namespace] = (array) $dirs;
137       }
138     }
139
140     return $plugin_namespaces;
141   }
142
143 }