From adc8b1e725f1565d871534afa489f33c80cbfec3 Mon Sep 17 00:00:00 2001 From: catch Date: Thu, 27 Dec 2012 22:24:32 +0000 Subject: [PATCH] Issue #1849752 by effulgentsia, Berdir: Abstract non-Drupal-specific parts of AnnotatedClassDiscovery into a Drupal\Component base class. --- .../Annotation/AnnotationInterface.php | 4 +- .../Drupal/Component/Annotation/Plugin.php | 72 +++++++++++ .../Discovery/AnnotatedClassDiscovery.php | 120 ++++++++++++++++++ core/lib/Drupal/Core/Annotation/Plugin.php | 60 +-------- .../Drupal/Core/Annotation/Translation.php | 2 +- .../Discovery/AnnotatedClassDiscovery.php | 93 +++----------- 6 files changed, 217 insertions(+), 134 deletions(-) rename core/lib/Drupal/{Core => Component}/Annotation/AnnotationInterface.php (66%) create mode 100644 core/lib/Drupal/Component/Annotation/Plugin.php create mode 100644 core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php diff --git a/core/lib/Drupal/Core/Annotation/AnnotationInterface.php b/core/lib/Drupal/Component/Annotation/AnnotationInterface.php similarity index 66% rename from core/lib/Drupal/Core/Annotation/AnnotationInterface.php rename to core/lib/Drupal/Component/Annotation/AnnotationInterface.php index 3382d4836b6..e3aacc68fbe 100644 --- a/core/lib/Drupal/Core/Annotation/AnnotationInterface.php +++ b/core/lib/Drupal/Component/Annotation/AnnotationInterface.php @@ -2,10 +2,10 @@ /** * @file - * Definition of Drupal\Core\Annotation\AnnotationInterface. + * Contains Drupal\Component\Annotation\AnnotationInterface. */ -namespace Drupal\Core\Annotation; +namespace Drupal\Component\Annotation; /** * Defines a common interface for classed annotations. diff --git a/core/lib/Drupal/Component/Annotation/Plugin.php b/core/lib/Drupal/Component/Annotation/Plugin.php new file mode 100644 index 00000000000..751eb20b781 --- /dev/null +++ b/core/lib/Drupal/Component/Annotation/Plugin.php @@ -0,0 +1,72 @@ +definition = $this->parse($values); + } + + /** + * Parses an annotation into its definition. + * + * @param array $values + * The annotation array. + * + * @return array + * The parsed annotation as a definition. + */ + protected function parse(array $values) { + $definitions = array(); + foreach ($values as $key => $value) { + if ($value instanceof AnnotationInterface) { + $definitions[$key] = $value->get(); + } + elseif (is_array($value)) { + $definitions[$key] = $this->parse($value); + } + else { + $definitions[$key] = $value; + } + } + return $definitions; + } + + /** + * Implements Drupal\Core\Annotation\AnnotationInterface::get(). + */ + public function get() { + return $this->definition; + } + +} diff --git a/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php new file mode 100644 index 00000000000..7e312314868 --- /dev/null +++ b/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -0,0 +1,120 @@ +pluginNamespaces = $plugin_namespaces; + $this->annotationNamespaces = $annotation_namespaces; + $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name; + } + + /** + * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition(). + */ + public function getDefinition($plugin_id) { + $plugins = $this->getDefinitions(); + return isset($plugins[$plugin_id]) ? $plugins[$plugin_id] : NULL; + } + + /** + * 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) { + 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; + $definitions[$definition['id']] = $definition; + } + } + } + } + } + } + return $definitions; + } + + /** + * Returns an array of PSR-0 namespaces to search for plugin classes. + */ + protected function getPluginNamespaces() { + return $this->pluginNamespaces; + } + + /** + * Returns an array of PSR-0 namespaces to search for annotation classes. + */ + protected function getAnnotationNamespaces() { + return $this->annotationNamespaces; + } + +} diff --git a/core/lib/Drupal/Core/Annotation/Plugin.php b/core/lib/Drupal/Core/Annotation/Plugin.php index d4931ee1228..4d1d1a629df 100644 --- a/core/lib/Drupal/Core/Annotation/Plugin.php +++ b/core/lib/Drupal/Core/Annotation/Plugin.php @@ -7,68 +7,12 @@ namespace Drupal\Core\Annotation; -use Drupal\Core\Annotation\AnnotationInterface; +use Drupal\Component\Annotation\Plugin as ComponentPlugin; /** * Defines a Plugin annotation object. * - * Annotations in plugin classes can utilize this class in order to pass - * various metadata about the plugin through the parser to - * DiscoveryInterface::getDefinitions() calls. This allows the metadata - * of a class to be located with the class itself, rather than in module-based - * info hooks. - * * @Annotation */ -class Plugin implements AnnotationInterface { - - /** - * The plugin definiton read from the class annotation. - * - * @var array - */ - protected $definition; - - /** - * Constructs a Plugin object. - * - * Builds up the plugin definition and invokes the get() method for any - * classed annotations that were used. - */ - public function __construct($values) { - $this->definition = $this->parse($values); - } - - /** - * Parses an annotation into its definition. - * - * @param array $values - * The annotation array. - * - * @return array - * The parsed annotation as a definition. - */ - protected function parse(array $values) { - $definitions = array(); - foreach ($values as $key => $value) { - if ($value instanceof AnnotationInterface) { - $definitions[$key] = $value->get(); - } - elseif (is_array($value)) { - $definitions[$key] = $this->parse($value); - } - else { - $definitions[$key] = $value; - } - } - return $definitions; - } - - /** - * Implements Drupal\Core\Annotation\AnnotationInterface::get(). - */ - public function get() { - return $this->definition; - } - +class Plugin extends ComponentPlugin { } diff --git a/core/lib/Drupal/Core/Annotation/Translation.php b/core/lib/Drupal/Core/Annotation/Translation.php index 1e4ec6da92d..0d6acd10dfa 100644 --- a/core/lib/Drupal/Core/Annotation/Translation.php +++ b/core/lib/Drupal/Core/Annotation/Translation.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Annotation; -use Drupal\Core\Annotation\AnnotationInterface; +use Drupal\Component\Annotation\AnnotationInterface; /** * Defines a translatable annotation object. diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php index bd89a92d8e9..0b387dc7e57 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -7,94 +7,41 @@ namespace Drupal\Core\Plugin\Discovery; -use DirectoryIterator; -use Drupal\Component\Plugin\Discovery\DiscoveryInterface; -use Drupal\Component\Reflection\MockFileFinder; -use Drupal\Core\Annotation\Plugin; -use Doctrine\Common\Annotations\AnnotationReader; -use Doctrine\Common\Annotations\AnnotationRegistry; -use Doctrine\Common\Reflection\StaticReflectionParser; +use Drupal\Component\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery; /** * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces. */ -class AnnotatedClassDiscovery implements DiscoveryInterface { +class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery { /** * Constructs an AnnotatedClassDiscovery object. */ - function __construct($owner, $type) { + function __construct($owner, $type, $root_namespaces = NULL) { $this->owner = $owner; $this->type = $type; + $this->rootNamespaces = $root_namespaces; + $annotation_namespaces = array( + 'Drupal\Component\Annotation' => DRUPAL_ROOT . '/core/lib', + 'Drupal\Core\Annotation' => DRUPAL_ROOT . '/core/lib', + ); + parent::__construct(array(), $annotation_namespaces, 'Drupal\Core\Annotation\Plugin'); } /** - * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition(). + * Overrides Drupal\Component\Plugin\Discovery\AnnotatedClassDiscovery::getPluginNamespaces(). + * + * This is overridden rather than set in the constructor, because Drupal + * modules can be enabled (and therefore, namespaces registered) during the + * lifetime of a plugin manager. */ - public function getDefinition($plugin_id) { - $plugins = $this->getDefinitions(); - return isset($plugins[$plugin_id]) ? $plugins[$plugin_id] : NULL; - } - - /** - * 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 namespace of classes that can be used for annotations. - AnnotationRegistry::registerAutoloadNamespace('Drupal\Core\Annotation', array(DRUPAL_ROOT . '/core/lib')); - // Get all PSR-0 namespaces. - $namespaces = drupal_classloader()->getNamespaces(); - foreach ($namespaces as $ns => $namespace_dirs) { - - // OS-Safe directory separators. - $ns = str_replace('\\', DIRECTORY_SEPARATOR, $ns); - - foreach ($namespace_dirs as $dir) { - // Check for the pre-determined directory structure to find plugins. - $prefix = implode(DIRECTORY_SEPARATOR, array( - $ns, - 'Plugin', - $this->owner, - $this->type - )); - $dir .= DIRECTORY_SEPARATOR . $prefix; - - // If the directory structure exists, look for classes. - if (file_exists($dir)) { - $directories = new DirectoryIterator($dir); - foreach ($directories as $fileinfo) { - // @todo Once core requires 5.3.6, use $fileinfo->getExtension(). - if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') { - $class = str_replace( - DIRECTORY_SEPARATOR, - '\\', - $prefix . DIRECTORY_SEPARATOR . $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(), 'Drupal\Core\Annotation\Plugin')) { - // AnnotationInterface::get() returns the array definition - // instead of requiring us to work with the annotation object. - $definition = $annotation->get(); - $definition['class'] = $class; - $definitions[$definition['id']] = $definition; - } - } - } - } - } + protected function getPluginNamespaces() { + $plugin_namespaces = array(); + $root_namespaces = isset($this->rootNamespaces) ? $this->rootNamespaces : drupal_classloader()->getNamespaces(); + foreach ($root_namespaces as $namespace => $dirs) { + $plugin_namespaces["$namespace\\Plugin\\{$this->owner}\\{$this->type}"] = $dirs; } - return $definitions; + return $plugin_namespaces; } }