diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php index 8a45afc..50c4635 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -8,6 +8,10 @@ namespace Drupal\Core\Plugin\Discovery; use Drupal\Component\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery; +use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\Common\Annotations\AnnotationRegistry; +use Drupal\Component\Reflection\MockFileFinder; +use Doctrine\Common\Reflection\StaticReflectionParser; /** * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces. @@ -63,6 +67,52 @@ function __construct($subdir, \Traversable $root_namespaces, $annotation_namespa } /** + * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions(). + */ + public function getDefinitions() { + $definitions = array(); + $reader = new AnnotationReader(); + // Prevent @endlink from being parsed as an annotation. + $reader->addGlobalIgnoredName('endlink'); + + // Register the namespaces of classes that can be used for annotations. + AnnotationRegistry::registerAutoloadNamespaces($this->getAnnotationNamespaces()); + + // Search for classes within all PSR-0 namespace locations. + foreach ($this->getPluginNamespaces() as $namespace => $dirs) { + // Extract the module name from this namespace. + $module = $this->getModuleFromNamespace($namespace); + foreach ($dirs as $dir) { + $dir .= DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $namespace); + if (file_exists($dir)) { + foreach (new \DirectoryIterator($dir) as $fileinfo) { + // @todo Once core requires 5.3.6, use $fileinfo->getExtension(). + if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') { + $class = $namespace . '\\' . $fileinfo->getBasename('.php'); + + // The filename is already known, so there is no need to find the + // file. However, StaticReflectionParser needs a finder, so use a + // mock version. + $finder = MockFileFinder::create($fileinfo->getPathName()); + $parser = new StaticReflectionParser($class, $finder); + + if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), $this->pluginDefinitionAnnotationName)) { + // AnnotationInterface::get() returns the array definition + // instead of requiring us to work with the annotation object. + $definition = $annotation->get(); + $definition['class'] = $class; + $definition['module'] = $module; + $definitions[$definition['id']] = $definition; + } + } + } + } + } + } + return $definitions; + } + + /** * {@inheritdoc} */ protected function getPluginNamespaces() { @@ -74,4 +124,23 @@ protected function getPluginNamespaces() { return $plugin_namespaces; } + /** + * Extracts a module name from a Drupal namespace. + * + * @param string $namespace + * The namespace to extract the module name from. + * + * @return string|null + * The matches module name, or NULL otherwise. + */ + protected function getModuleFromNamespace($namespace) { + preg_match('|^Drupal\\\\(?[\w]+)\\\\|', $namespace, $matches); + + if (isset($matches['module'])) { + return $matches['module']; + } + + return NULL; + } + }