- Patch #1683644 by chx, EclipseGc, tim.plunkett, aspilicious, xjm, dawehner, effulgentsia: use Annotations for plugin discovery.
parent
63d52d0629
commit
0033bac993
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\Component\Reflection\MockFileFinder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Component\Reflection;
|
||||||
|
|
||||||
|
use Doctrine\Common\Reflection\ClassFinderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a mock file finder that only returns a single filename.
|
||||||
|
*
|
||||||
|
* This can be used with Doctrine\Common\Reflection\StaticReflectionParser if
|
||||||
|
* the filename is known and inheritance is not a concern (for example, if
|
||||||
|
* only the class annotation is needed).
|
||||||
|
*/
|
||||||
|
class MockFileFinder implements ClassFinderInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The only filename this finder ever returns.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $filename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a MockFileFinder object.
|
||||||
|
*/
|
||||||
|
public function __construct($prefixes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Doctrine\Common\Reflection\ClassFinderInterface::findFile().
|
||||||
|
*/
|
||||||
|
public function findFile($class) {
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new mock file finder objects.
|
||||||
|
*/
|
||||||
|
static public function create($filename) {
|
||||||
|
$object = new static(array());
|
||||||
|
$object->filename = $filename;
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\Core\Annotation\AnnotationInterface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\Annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a common interface for classed annotations.
|
||||||
|
*/
|
||||||
|
interface AnnotationInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of an annotation.
|
||||||
|
*/
|
||||||
|
public function get();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\Core\Annotation\Plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\Annotation;
|
||||||
|
|
||||||
|
use Drupal\Core\Annotation\AnnotationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if ($value instanceof AnnotationInterface) {
|
||||||
|
$this->definition[$key] = $value->get();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->definition[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Drupal\Core\Annotation\AnnotationInterface::get().
|
||||||
|
*/
|
||||||
|
public function get() {
|
||||||
|
return $this->definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\Core\Annotation\Translation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\Annotation;
|
||||||
|
|
||||||
|
use Drupal\Core\Annotation\AnnotationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a translatable annotation object.
|
||||||
|
*
|
||||||
|
* Some metadata within an annotation needs to be translatable. This class
|
||||||
|
* supports that need by allowing both the translatable string and, if
|
||||||
|
* specified, a context for that string. This class is essentially a wrapper
|
||||||
|
* around the traditional t() function in drupal.
|
||||||
|
*
|
||||||
|
* @Annotation
|
||||||
|
*/
|
||||||
|
class Translation implements AnnotationInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The translation of the value passed to the constructor of the class.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $translation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Translation object.
|
||||||
|
*
|
||||||
|
* Parses values passed into this class through the t() function in Drupal and
|
||||||
|
* handles an optional context for the string.
|
||||||
|
*/
|
||||||
|
public function __construct($values) {
|
||||||
|
$string = $values['value'];
|
||||||
|
$options = array();
|
||||||
|
if (!empty($values['context'])) {
|
||||||
|
$options = array(
|
||||||
|
'context' => $values['context'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->translation = t($string, array(), $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Drupal\Core\Annotation\AnnotationInterface::get().
|
||||||
|
*/
|
||||||
|
public function get() {
|
||||||
|
return $this->translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
|
||||||
|
*/
|
||||||
|
class AnnotatedClassDiscovery implements DiscoveryInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an AnnotatedClassDiscovery object.
|
||||||
|
*/
|
||||||
|
function __construct($owner, $type) {
|
||||||
|
$this->owner = $owner;
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
|
||||||
|
*/
|
||||||
|
public function getDefinition($plugin_id) {
|
||||||
|
$plugins = $this->getDefinitions();
|
||||||
|
return isset($plugins[$plugin_id]) ? $plugins[$plugin_id] : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
|
||||||
|
*/
|
||||||
|
public function getDefinitions() {
|
||||||
|
$definitions = array();
|
||||||
|
$reader = new AnnotationReader();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue