9ecbaa05375428543655d307aa94373c2aa4fd47
[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 use Drupal\Component\Utility\Unicode;
8
9 /**
10  * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
11  */
12 class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
13
14   /**
15    * A suffix to append to each PSR-4 directory associated with a base
16    * namespace, to form the directories where plugins are found.
17    *
18    * @var string
19    */
20   protected $directorySuffix = '';
21
22   /**
23    * A suffix to append to each base namespace, to obtain the namespaces where
24    * plugins are found.
25    *
26    * @var string
27    */
28   protected $namespaceSuffix = '';
29
30   /**
31    * A list of base namespaces with their PSR-4 directories.
32    *
33    * @var \Traversable
34    */
35   protected $rootNamespacesIterator;
36
37   /**
38    * Constructs an AnnotatedClassDiscovery object.
39    *
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.
52    */
53   public function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) {
54     if ($subdir) {
55       // Prepend a directory separator to $subdir,
56       // if it does not already have one.
57       if ('/' !== $subdir[0]) {
58         $subdir = '/' . $subdir;
59       }
60       $this->directorySuffix = $subdir;
61       $this->namespaceSuffix = str_replace('/', '\\', $subdir);
62     }
63     $this->rootNamespacesIterator = $root_namespaces;
64     $plugin_namespaces = [];
65     parent::__construct($plugin_namespaces, $plugin_definition_annotation_name, $annotation_namespaces);
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   protected function getAnnotationReader() {
72     if (!isset($this->annotationReader)) {
73       $reader = parent::getAnnotationReader();
74
75       // Add the Core annotation classes like @Translation.
76       $reader->addNamespace('Drupal\Core\Annotation');
77       $this->annotationReader = $reader;
78     }
79     return $this->annotationReader;
80   }
81
82   /**
83    * {@inheritdoc}
84    */
85   protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) {
86     parent::prepareAnnotationDefinition($annotation, $class);
87
88     if (!$annotation->getProvider()) {
89       $annotation->setProvider($this->getProviderFromNamespace($class));
90     }
91   }
92
93   /**
94    * Extracts the provider name from a Drupal namespace.
95    *
96    * @param string $namespace
97    *   The namespace to extract the provider from.
98    *
99    * @return string|null
100    *   The matching provider name, or NULL otherwise.
101    */
102   protected function getProviderFromNamespace($namespace) {
103     preg_match('|^Drupal\\\\(?<provider>[\w]+)\\\\|', $namespace, $matches);
104
105     if (isset($matches['provider'])) {
106       return Unicode::strtolower($matches['provider']);
107     }
108
109     return NULL;
110   }
111
112   /**
113    * {@inheritdoc}
114    */
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;
129         }
130       }
131     }
132     else {
133       // Both the namespace suffix and the directory suffix are empty,
134       // so the plugin namespaces and directories are the same as the base
135       // directories.
136       foreach ($this->rootNamespacesIterator as $namespace => $dirs) {
137         $plugin_namespaces[$namespace] = (array) $dirs;
138       }
139     }
140
141     return $plugin_namespaces;
142   }
143
144 }