diff --git a/composer.json b/composer.json
index 97ef123..940e9d0 100644
--- a/composer.json
+++ b/composer.json
@@ -3,6 +3,12 @@
"description": "Drupal is an open source content management platform powering millions of websites and applications.",
"type": "drupal-core",
"license": "GPL-2.0+",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/donquixote/krautoload"
+ }
+ ],
"require": {
"symfony/class-loader": "2.3.*",
"symfony/dependency-injection": "2.3.*",
@@ -20,7 +26,8 @@
"symfony-cmf/routing": "1.1.*@alpha",
"easyrdf/easyrdf": "0.8.*@beta",
"phpunit/phpunit": "3.7.*",
- "zendframework/zend-feed": "2.2.*"
+ "zendframework/zend-feed": "2.2.*",
+ "donquixote/krautoload": "0.0.*@alpha"
},
"autoload": {
"psr-0": {
diff --git a/composer.lock b/composer.lock
index 75394ba..3b84c49 100644
--- a/composer.lock
+++ b/composer.lock
@@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
- "hash": "9cad5a32fc0b4c0fac16fbda1b8ead16",
+ "hash": "7498cf0dce7a852d3dbeb5681515ed0a",
"packages": [
{
"name": "doctrine/common",
@@ -75,6 +75,58 @@
"time": "2012-09-19 22:55:18"
},
{
+ "name": "donquixote/krautoload",
+ "version": "0.0.1-alpha7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/donquixote/krautoload.git",
+ "reference": "0.0.1-alpha7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/donquixote/krautoload/zipball/0.0.1-alpha7",
+ "reference": "0.0.1-alpha7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/php-invoker": ">=1.1.2",
+ "phpunit/phpunit": ">=3.7"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Krautoload\\": "src/"
+ }
+ },
+ "license": [
+ "GPL"
+ ],
+ "authors": [
+ {
+ "name": "Andreas Hennings",
+ "homepage": "http://github.com/donquixote"
+ }
+ ],
+ "description": "Krautoload is a pluggable class loader and class discovery tool.",
+ "homepage": "http://github.com/donquixote/krautoload",
+ "keywords": [
+ "PEAR",
+ "PSR-0",
+ "PSR-4",
+ "PSR-X",
+ "autoload",
+ "classloader"
+ ],
+ "support": {
+ "issues": "http://github.com/donquixote/krautoload/issues",
+ "source": "https://github.com/donquixote/krautoload/tree/0.0.1-alpha7"
+ },
+ "time": "2013-07-18 21:43:11"
+ },
+ {
"name": "easyrdf/easyrdf",
"version": "0.8.0-beta.1",
"source": {
@@ -1685,7 +1737,8 @@
"stability-flags": {
"kriswallsmith/assetic": 15,
"symfony-cmf/routing": 15,
- "easyrdf/easyrdf": 10
+ "easyrdf/easyrdf": 10,
+ "donquixote/krautoload": 15
},
"platform": [
diff --git a/core/core.services.yml b/core/core.services.yml
index 640440b..7a01843 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -153,7 +153,9 @@ services:
- [addSubscriber, ['@http_client_simpletest_subscriber']]
- [setUserAgent, ['Drupal (+http://drupal.org/)']]
container.namespaces:
- class: ArrayObject
+ class: Drupal\Core\ClassLoader\SearchableNamespacesInterface
+ factory_service: class_loader
+ factory_method: buildSearchableNamespaces
arguments: [ '%container.namespaces%' ]
tags:
- { name: persist }
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 9daa71a..b35779e 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -22,6 +22,8 @@
use Drupal\Core\Lock\DatabaseLockBackend;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Session\UserSession;
+use Drupal\Core\ClassLoader\NamespaceInspectorAdapter;
+use Drupal\Core\ClassLoader\NamespaceInspectorAdapterInterface;
/**
* @file
@@ -2742,61 +2744,78 @@ function arg($index = NULL, $path = NULL) {
}
/**
- * Initializes and returns the class loader.
+ * Initializes the class loader, and return an object to controll the class
+ * loader.
*
- * The class loader is responsible for lazy-loading all PSR-0 compatible
- * classes, interfaces, and traits (PHP 5.4 and later). It's only dependency
- * is DRUPAL_ROOT. Otherwise it may be called as early as possible.
+ * The class loader is responsible for lazy-loading all classes, interfaces, and
+ * traits (PHP 5.4 and later) that cannot be loaded in other ways.
+ * It may be called as soon as the DRUPAL_ROOT constant is available.
+ * (defined in
+ * Its only dependency is DRUPAL_ROOT. Otherwise it may be called as early as possible.
*
- * @param $class_loader
+ * @param $loader_name
* The name of class loader to use. This can be used to change the class
* loader class when calling drupal_classloader() from settings.php. It is
* ignored otherwise.
*
- * @return \Symfony\Component\ClassLoader\ClassLoader
- * A ClassLoader class instance (or extension thereof).
+ * @return NamespaceInspectorAdapter
+ * A wrapper around the class loader, with methods to register classes,
+ * namespaces and prefixes.
*/
-function drupal_classloader($class_loader = NULL) {
- // By default, use the ClassLoader which is best for development, as it does
- // not break when code is moved on the file system. However, as it is slow,
- // allow to use the APC class loader in production.
- static $loader;
+function drupal_classloader($loader_name = NULL) {
+ /**
+ * @var NamespaceInspectorAdapter $adapter
+ */
+ static $adapter;
- if (!isset($loader)) {
+ // Initialize the class loader, if it is not already initialized.
+ if (!isset($adapter)) {
- // Include the Symfony ClassLoader for loading PSR-0-compatible classes.
- require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassLoader.php';
- $loader = new ClassLoader();
+ // Include the bootstrap include file for the Krautoload ClassLoader.
+ // Drupal 8 uses Krautoload instead of the loader shipped with Symfony or
+ // Composer, to have PSR-4 support and class discovery.
+ require_once DRUPAL_ROOT . '/core/vendor/donquixote/krautoload/src/Krautoload.php';
- // Register the class loader.
- // When configured to use APC, the ApcClassLoader is registered instead.
- // Note that ApcClassLoader decorates ClassLoader and only provides the
- // findFile() method, but none of the others. The actual registry is still
- // in ClassLoader.
- if (!isset($class_loader)) {
- $class_loader = settings()->get('class_loader', 'default');
+ // Check class loader setting, to determine which variation of the class
+ // loader to use.
+ if (!isset($loader_name)) {
+ $loader_name = settings()->get('class_loader', 'default');
}
- if ($class_loader === 'apc') {
- require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php';
- $apc_loader = new ApcClassLoader('drupal.' . drupal_get_hash_salt(), $loader);
- $apc_loader->register();
- }
- else {
- $loader->register();
+
+ // Prepare an options array to initialize Krautoload.
+ $krautoload_options = array();
+ // Use a discovery-enabled version of the class loader.
+ $krautoload_options['introspection'] = TRUE;
+ // Activate APC cache, if available.
+ if ($loader_name === 'apc' && extension_enabled('apc') && function_exists('apc_store')) {
+ $krautoload_options['cache'] = 'ApcCache';
+ $krautoload_options['cache_prefix'] = 'drupal.' . drupal_get_hash_salt();
}
- // Register namespaces for vendor libraries managed by Composer.
- $prefixes_and_namespaces = require DRUPAL_ROOT . '/core/vendor/composer/autoload_namespaces.php';
- $loader->addPrefixes($prefixes_and_namespaces);
+ // Bootstrap Krautoload with these options.
+ // The return value is a "RegistrationHub" object, which has various methods
+ // to register namespaces and other things, but is not the main class loader
+ // object. Within Drupal, this is being referred to as "$loader_controller".
+ $adapter = Krautoload::start($krautoload_options);
- // Register the loader with PHP.
- $loader->register();
+ // Register class loading for vendor libraries managed by Composer.
+ // This will process
+ // - core/vendor/composer/autoload_namespaces.php
+ // - core/vendor/composer/autoload_classmap.php
+ // This will also work with a generated classmap from
+ // "composer install --optimize-autoloader".
+ $adapter->composerVendorDir(DRUPAL_ROOT . '/core/vendor');
+
+ // Replace the adapter with a Drupal-native one.
+ $adapter = new NamespaceInspectorAdapter($adapter->getInspector());
}
- return $loader;
+
+ return $adapter;
}
/**
- * Registers an additional namespace.
+ * Registers class loading for a Drupal extension.
+ * (module, theme or install profile)
*
* @param string $name
* The namespace component to register; e.g., 'node'.
@@ -2804,8 +2823,7 @@ function drupal_classloader($class_loader = NULL) {
* The relative path to the Drupal component in the filesystem.
*/
function drupal_classloader_register($name, $path) {
- $loader = drupal_classloader();
- $loader->addPrefix('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib');
+ drupal_classloader()->addDrupalExtension($name, $path);
}
/**
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php
index 13f853d..6ebff5a 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php
@@ -7,12 +7,9 @@
namespace Drupal\Component\Plugin\Discovery;
-use DirectoryIterator;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
-use Drupal\Component\Reflection\MockFileFinder;
-use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
-use Doctrine\Common\Reflection\StaticReflectionParser;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
@@ -20,16 +17,25 @@
class AnnotatedClassDiscovery implements DiscoveryInterface {
/**
- * The namespaces within which to find plugin classes.
+ * An object containing the base namespaces from which the plugin namespaces
+ * are built by appending the namespace suffix.
*
- * @var array
+ * @var SearchableNamespacesInterface
*/
- protected $pluginNamespaces;
+ protected $rootNamespaces;
+
+ /**
+ * Suffix to be appended to each base namespace,
+ * to obtain the plugin namespaces.
+ *
+ * @var string
+ */
+ protected $namespaceSuffix;
/**
* The namespaces of classes that can be used as annotations.
*
- * @var array
+ * @var SearchableNamespacesInterface
*/
protected $annotationNamespaces;
@@ -46,23 +52,34 @@ class AnnotatedClassDiscovery implements DiscoveryInterface {
/**
* Constructs an AnnotatedClassDiscovery object.
*
- * @param array $plugin_namespaces
- * (optional) An array of namespace that may contain plugin implementations.
- * Defaults to an empty array.
- * @param array $annotation_namespaces
- * (optional) The namespaces of classes that can be used as annotations.
- * Defaults to an empty array.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable base namespaces from which the plugin namespaces are built.
+ * @param string $namespace_suffix
+ * Namespace suffix to be appended to each base plugin namespace, to obtain
+ * the plugin namespaces that will be searched for plugin classes.
* @param string $plugin_definition_annotation_name
- * (optional) The name of the annotation that contains the plugin definition.
- * Defaults to 'Drupal\Component\Annotation\Plugin'.
+ * The name of the annotation that contains the plugin definition.
*/
- function __construct($plugin_namespaces = array(), $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
- $this->pluginNamespaces = $plugin_namespaces;
- $this->annotationNamespaces = $annotation_namespaces;
+ function __construct(SearchableNamespacesInterface $root_namespaces, $namespace_suffix, $plugin_definition_annotation_name) {
+ $this->rootNamespaces = $root_namespaces;
+ $this->namespaceSuffix = $namespace_suffix;
+ // Initialize with an empty collection of annotation namespaces.
+ // More namespaces can be added with addAnnotationNamespace().
+ $this->annotationNamespaces = $root_namespaces->buildSearchableNamespaces();
$this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
}
/**
+ * Add an annotation namespace, after the object has been created.
+ *
+ * @param string $namespace
+ * Annotation namespace to add.
+ */
+ public function addAnnotationNamespace($namespace) {
+ $this->annotationNamespaces->addNamespace($namespace);
+ }
+
+ /**
* Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
*/
public function getDefinition($plugin_id) {
@@ -74,58 +91,32 @@ public function getDefinition($plugin_id) {
* 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');
- $reader->addGlobalIgnoredName('file');
// 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;
+ AnnotationRegistry::reset();
+ AnnotationRegistry::registerLoader(array($this->getAnnotationNamespaces(), 'classExistsInNamespaces'));
+
+ // Scan namespaces.
+ $discoveryAPI = new ClassFileVisitorAPI($this->pluginDefinitionAnnotationName);
+ $this->getPluginNamespaces()->apiVisitClassFiles($discoveryAPI, FALSE);
+ return $discoveryAPI->getDefinitions();
}
/**
* Returns an array of PSR-0 namespaces to search for plugin classes.
+ *
+ * @return SearchableNamespacesInterface
*/
protected function getPluginNamespaces() {
- return $this->pluginNamespaces;
+ return $this->rootNamespaces->buildFromSuffix('\\' . $this->namespaceSuffix);
}
/**
- * Returns an array of PSR-0 namespaces to search for annotation classes.
+ * Returns a searchable namespace collection to search for annotation classes.
+ *
+ * @return SearchableNamespacesInterface
*/
protected function getAnnotationNamespaces() {
return $this->annotationNamespaces;
}
-
}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/ClassFileVisitorAPI.php b/core/lib/Drupal/Component/Plugin/Discovery/ClassFileVisitorAPI.php
new file mode 100644
index 0000000..9331f97
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/ClassFileVisitorAPI.php
@@ -0,0 +1,109 @@
+reader = new AnnotationReader();
+ // Prevent @endlink and @file from being parsed as an annotation.
+ $this->reader->addGlobalIgnoredName('endlink');
+ $this->reader->addGlobalIgnoredName('file');
+ $this->annotationName = $annotationName;
+ }
+
+ /**
+ * Get the array of plugin definitions, after everything is scanned.
+ *
+ * @return array
+ */
+ public function getDefinitions() {
+ return $this->definitions;
+ }
+
+ /**
+ * The directory scan has found a file,
+ * which is expected to define the given class.
+ *
+ * @param string $file
+ * @param string $relativeClassName
+ * Classes that could be in this file according to PSR-0 mapping.
+ * This array is never empty.
+ * The first class in this array is always the class which has no
+ * underscores after the last namespace separator.
+ */
+ public function fileWithClass($file, $relativeClassName) {
+ $this->parseFileWithClass($file, $relativeClassName);
+ }
+
+ /**
+ * The directory scan has found a file,
+ * which may define any or none of the given classes.
+ *
+ * @param string $file
+ * @param array $relativeClassNames
+ * Classes that could be in this file according to PSR-0 mapping.
+ * This array is never empty.
+ * The first class in this array is always the class which has no
+ * underscores after the last namespace separator.
+ */
+ public function fileWithClassCandidates($file, array $relativeClassNames) {
+ // Only pick the first class, which is the no-underscore version.
+ $this->parseFileWithClass($file, $relativeClassNames[0]);
+ }
+
+ /**
+ * The directory scan has found a file which is expected to define the given
+ * class.
+ *
+ * @param string $file
+ * @param string $relativeClassName
+ */
+ protected function parseFileWithClass($file, $relativeClassName) {
+ $class = $this->getNamespace() . $relativeClassName;
+ if ($annotation = $this->extractClassAnnotation($file, $class)) {
+ // AnnotationInterface::get() returns the array definition
+ // instead of requiring us to work with the annotation object.
+ $definition = $annotation->get();
+ $definition['class'] = $class;
+ $this->definitions[$definition['id']] = $definition;
+ }
+ }
+
+ /**
+ * Parse a class file, to extract the annotation.
+ *
+ * @param string $file
+ * @param string $class
+ * @return mixed
+ * The annotation as returned by AnnotationReader::getClassAnnotation(),
+ * or NULL.
+ */
+ protected function extractClassAnnotation($file, $class) {
+ // 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($file);
+ $parser = new StaticReflectionParser($class, $finder);
+ return $this->reader->getClassAnnotation($parser->getReflectionClass(), $this->annotationName);
+ }
+}
diff --git a/core/lib/Drupal/Core/Action/ActionManager.php b/core/lib/Drupal/Core/Action/ActionManager.php
index c987d8c..5847f44 100644
--- a/core/lib/Drupal/Core/Action/ActionManager.php
+++ b/core/lib/Drupal/Core/Action/ActionManager.php
@@ -11,6 +11,7 @@
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Provides an Action plugin manager.
@@ -23,12 +24,13 @@ class ActionManager extends PluginManagerBase {
/**
* Constructs a ActionManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $this->discovery = new AnnotatedClassDiscovery('Action', $namespaces, array(), 'Drupal\Core\Annotation\Action');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'Action', 'Drupal\Core\Annotation\Action');
$this->discovery = new AlterDecorator($this->discovery, 'action_info');
$this->factory = new ContainerFactory($this);
diff --git a/core/lib/Drupal/Core/Archiver/ArchiverManager.php b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
index f3bfc96..4c7f30c 100644
--- a/core/lib/Drupal/Core/Archiver/ArchiverManager.php
+++ b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
@@ -11,6 +11,7 @@
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Archiver plugin manager.
@@ -20,9 +21,10 @@ class ArchiverManager extends DefaultPluginManager {
/**
* Constructs a ArchiverManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
@@ -30,8 +32,8 @@ class ArchiverManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
- parent::__construct('Archiver', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'Archiver');
$this->alterInfo($module_handler, 'archiver_info');
$this->setCacheBackend($cache_backend, $language_manager, 'archiver_info');
}
diff --git a/core/lib/Drupal/Core/ClassLoader/ClassLoaderAdapterInterface.php b/core/lib/Drupal/Core/ClassLoader/ClassLoaderAdapterInterface.php
new file mode 100644
index 0000000..46bbc63
--- /dev/null
+++ b/core/lib/Drupal/Core/ClassLoader/ClassLoaderAdapterInterface.php
@@ -0,0 +1,39 @@
+addNamespacePSR0('Drupal\\' . $extension_name, DRUPAL_ROOT . '/' . $extension_dir . '/lib');
+
+ // Register the extension's "src/" directory for PSR-4 class loading.
+ // @todo
+ // - Make a choice between "src/" and "lib/" for PSR-4 classes.
+ // - Have a transition phase to migrate modules to PSR-4.
+ // - Remove PSR-0 after this transition phase.
+ $this->addNamespacePSRX('Drupal\\' . $extension_name, DRUPAL_ROOT . '/' . $extension_dir . '/src');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addDrupalExtensionTests($extension_name, $extension_dir) {
+ $this->addNamespacePSR0('Drupal\\' . $extension_name . '\\Tests', DRUPAL_ROOT . '/' . $extension_dir . '/tests');
+ $this->addNamespacePSRX('Drupal\\' . $extension_name . '\\Tests', DRUPAL_ROOT . '/' . $extension_dir . '/tests/src');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addDrupalExtensionsByFileName(array $extension_filenames) {
+ foreach ($extension_filenames as $extension_name => $extension_filename) {
+ $this->addDrupalExtension($extension_name, dirname($extension_filename));
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addDrupalCore() {
+ $this->addNamespacePSR0('Drupal\Component', DRUPAL_ROOT . '/core/lib');
+ $this->addNamespacePSR0('Drupal\Core', DRUPAL_ROOT . '/core/lib');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addDrupalCoreTests() {
+ $this->addNamespacePSR0('Drupal\\Tests', DRUPAL_ROOT . '/core/tests');
+ }
+
+ /**
+ * @param array $namespaces
+ * @return SearchableNamespacesInterface
+ * @throws \Exception
+ */
+ function buildSearchableNamespaces(array $namespaces = array()) {
+ $searchable = new SearchableNamespaces($this->finder);
+ $searchable->addNamespaces($namespaces);
+ return $searchable;
+ }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/ClassLoader/NamespaceInspectorAdapterInterface.php b/core/lib/Drupal/Core/ClassLoader/NamespaceInspectorAdapterInterface.php
new file mode 100644
index 0000000..88d7a1e
--- /dev/null
+++ b/core/lib/Drupal/Core/ClassLoader/NamespaceInspectorAdapterInterface.php
@@ -0,0 +1,15 @@
+alterInfo($module_handler, 'condition_info');
$this->setCacheBackend($cache_backend, $language_manager, 'condition');
- $annotation_namespaces = array(
- 'Drupal\Core\Condition\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
- parent::__construct('Condition', $namespaces, $annotation_namespaces, 'Drupal\Core\Condition\Annotation\Condition');
+ parent::__construct($root_namespaces, 'Condition', array('Drupal\Core\Condition\Annotation'), 'Drupal\Core\Condition\Annotation\Condition');
}
/**
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index af1fe52..9170c55 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -12,7 +12,7 @@
use Drupal\Core\CoreServiceProvider;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\YamlFileLoader;
-use Symfony\Component\ClassLoader\ClassLoader;
+use Drupal\Core\ClassLoader\NamespaceInspectorAdapter;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -97,7 +97,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
/**
* The classloader object.
*
- * @var \Symfony\Component\ClassLoader\ClassLoader
+ * @var NamespaceInspectorAdapter
*/
protected $classLoader;
@@ -150,7 +150,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* String indicating the environment, e.g. 'prod' or 'dev'. Used by
* Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
* this value currently. Pass 'prod'.
- * @param \Symfony\Component\ClassLoader\ClassLoader $class_loader
+ * @param NamespaceInspectorAdapter $class_loader
* (optional) The classloader is only used if $storage is not given or
* the load from storage fails and a container rebuild is required. In
* this case, the loaded modules will be registered with this loader in
@@ -159,7 +159,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
*/
- public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE) {
+ public function __construct($environment, $class_loader, $allow_dumping = TRUE) {
$this->environment = $environment;
$this->booted = false;
$this->classLoader = $class_loader;
@@ -233,7 +233,7 @@ public function discoverServiceProviders() {
$this->moduleList = isset($module_list['enabled']) ? $module_list['enabled'] : array();
}
$module_filenames = $this->getModuleFileNames();
- $this->registerNamespaces($this->getModuleNamespaces($module_filenames));
+ $this->classLoader->addDrupalExtensionsByFileName($module_filenames);
// Load each module's serviceProvider class.
foreach ($this->moduleList as $module => $weight) {
@@ -417,8 +417,7 @@ protected function initializeContainer() {
// All namespaces must be registered before we attempt to use any service
// from the container.
$container_modules = $this->container->getParameter('container.modules');
- $namespaces_before = $this->classLoader->getPrefixes();
- $this->registerNamespaces($this->getModuleNamespaces($container_modules));
+ $this->classLoader->addDrupalExtensionsByFileName($container_modules);
// If 'container.modules' is wrong, the container must be rebuilt.
if (!isset($this->moduleList)) {
@@ -427,13 +426,20 @@ protected function initializeContainer() {
if (array_keys($this->moduleList) !== array_keys($container_modules)) {
$persist = $this->getServicesToPersist();
unset($this->container);
- // Revert the class loader to its prior state. However,
- // registerNamespaces() performs a merge rather than replace, so to
- // effectively remove erroneous registrations, we must replace them with
- // empty arrays.
- $namespaces_after = $this->classLoader->getPrefixes();
- $namespaces_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array());
- $this->registerNamespaces($namespaces_before);
+ // @todo At this point, previous versions did attempt to revert the
+ // class loader to its previous state, with the intention to remove
+ // erroneous registrations.
+ // However, we can assume that this did not work, because
+ // \Symfony\Component\ClassLoader\ClassLoader does not support removal
+ // of registered namespaces, it only allows adding them.
+ // The other question is, whether removal of namespace registrations
+ // is desirable in the first place. Some of the classes might already
+ // be included, and removal of the namespace cannot undo that.
+ // A more interesting case is if a module has moved to a different
+ // directory. This case is not even detected in the if() clause above.
+ //
+ // Conclusion: A revert mechanic can be added, but needs to be
+ // discussed first.
}
}
@@ -441,11 +447,13 @@ protected function initializeContainer() {
$this->container = $this->buildContainer();
$this->persistServices($persist);
- // The namespaces are marked as persistent, so objects like the annotated
- // class discovery still has the right object. We may have updated the
- // list of modules, so set it.
+ // The searchable namespaces collection is marked as persistent, so
+ // objects like the annotated class discovery still have the right object.
if ($this->container->initialized('container.namespaces')) {
- $this->container->get('container.namespaces')->exchangeArray($this->container->getParameter('container.namespaces'));
+ // The list of namespaces may have changed, so set it.
+ $this->container->get('container.namespaces')->setNamespaces($this->container->getParameter('container.namespaces'));
+ // There may be a new class loader, so set it.
+ $this->container->get('container.namespaces')->setFinder($this->classLoader->getFinder());
}
if ($this->allowDumping) {
@@ -457,6 +465,7 @@ protected function initializeContainer() {
// Set the class loader which was registered as a synthetic service.
$this->container->set('class_loader', $this->classLoader);
+
// If we have a request set it back to the new container.
if (isset($request)) {
$this->container->enterScope('request');
@@ -507,21 +516,11 @@ protected function buildContainer() {
$container->setParameter('container.modules', $this->getModuleFileNames());
// Get a list of namespaces and put it onto the container.
- $namespaces = $this->getModuleNamespaces($this->getModuleFileNames());
- // Add all components in \Drupal\Core and \Drupal\Component that have a
- // Plugin directory.
- foreach (array('Core', 'Component') as $parent_directory) {
- $path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory;
- foreach (new \DirectoryIterator($path) as $component) {
- if (!$component->isDot() && is_dir($component->getPathname() . '/Plugin')) {
- $namespaces['Drupal\\' . $parent_directory .'\\' . $component->getFilename()] = DRUPAL_ROOT . '/core/lib';
- }
- }
- }
+ $namespaces = $this->getDiscoveryBaseNamespaces();
$container->setParameter('container.namespaces', $namespaces);
// Register synthetic services.
- $container->register('class_loader', 'Symfony\Component\ClassLoader\ClassLoader')->setSynthetic(TRUE);
+ $container->register('class_loader', 'Drupal\Core\ClassLoader\NamespaceInspectorAdapterInterface')->setSynthetic(TRUE);
$container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
$container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
$yaml_loader = new YamlFileLoader($container);
@@ -647,20 +646,30 @@ protected function getModuleFileNames() {
}
/**
- * Gets the namespaces of each enabled module.
+ * Gets the root namespaces that are used for plugin discovery.
+ *
+ * @return array
+ * Array of namespaces, keys are identical to the values.
*/
- protected function getModuleNamespaces($moduleFileNames) {
+ protected function getDiscoveryBaseNamespaces() {
$namespaces = array();
- foreach ($moduleFileNames as $module => $filename) {
- $namespaces["Drupal\\$module"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib';
+
+ // Collect root namespaces for extensions.
+ foreach ($this->getModuleFileNames() as $module => $filename) {
+ $namespaces[] = 'Drupal\\' . $module;
}
- return $namespaces;
- }
- /**
- * Registers a list of namespaces.
- */
- protected function registerNamespaces(array $namespaces = array()) {
- $this->classLoader->addPrefixes($namespaces);
+ // Add all components in \Drupal\Core and \Drupal\Component that have a
+ // Plugin directory.
+ foreach (array('Core', 'Component') as $parent_directory) {
+ $path = DRUPAL_ROOT . '/core/lib/Drupal/' . $parent_directory;
+ foreach (new \DirectoryIterator($path) as $component) {
+ if (!$component->isDot() && is_dir($component->getPathname() . '/Plugin')) {
+ $namespaces[] = 'Drupal\\' . $parent_directory . '\\' . $component->getFilename();
+ }
+ }
+ }
+
+ return $namespaces;
}
}
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 4766a91..aaef43c 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -19,6 +19,7 @@
use Drupal\Core\Plugin\Discovery\InfoHookDecorator;
use Drupal\Core\Cache\CacheBackendInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages entity type plugin definitions.
@@ -90,9 +91,10 @@ class EntityManager extends PluginManagerBase {
/**
* Constructs a new Entity plugin manager.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The service container this object should use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -102,17 +104,15 @@ class EntityManager extends PluginManagerBase {
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
- public function __construct(\Traversable $namespaces, ContainerInterface $container, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager) {
- // Allow the plugin definition to be altered by hook_entity_info_alter().
- $annotation_namespaces = array(
- 'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
+ public function __construct(SearchableNamespacesInterface $root_namespaces, ContainerInterface $container, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager) {
$this->moduleHandler = $module_handler;
$this->cache = $cache;
$this->languageManager = $language_manager;
- $this->discovery = new AnnotatedClassDiscovery('Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'Core\Entity', 'Drupal\Core\Entity\Annotation\EntityType');
+ $this->discovery->addAnnotationNamespace('Drupal\Core\Entity\Annotation');
+ // Allow the plugin definition to be altered by hook_entity_info_alter().
$this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
$this->discovery = new AlterDecorator($this->discovery, 'entity_info');
$this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Entity/Field/FieldTypePluginManager.php
index 9f9ceb8..de0f3c9 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldTypePluginManager.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldTypePluginManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\field\Plugin\Type\FieldType\LegacyFieldTypeDiscoveryDecorator;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin manager for 'field type' plugins.
@@ -31,9 +32,10 @@ class FieldTypePluginManager extends DefaultPluginManager {
/**
* Constructs the FieldTypePluginManager object
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
@@ -41,11 +43,8 @@ class FieldTypePluginManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface
* The module handler.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
- $annotation_namespaces = array(
- 'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
- parent::__construct('field/field_type', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\FieldType');
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'field\field_type', array('Drupal\Core\Entity\Annotation'), 'Drupal\Core\Entity\Annotation\FieldType');
$this->alterInfo($module_handler, 'field_info');
$this->setCacheBackend($cache_backend, $language_manager, 'field_types');
diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php
index 7857f7a..aff6140 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php
@@ -12,6 +12,7 @@
use Drupal\Core\Plugin\DefaultPluginManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages discovery and instantiation of menu local action plugins.
@@ -47,9 +48,10 @@ class LocalActionManager extends DefaultPluginManager {
/**
* Constructs a LocalActionManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface $controller_resolver
* An object to use in introspecting route methods.
* @param \Symfony\Component\HttpFoundation\Request $request
@@ -58,8 +60,8 @@ class LocalActionManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
- public function __construct(\Traversable $namespaces, ControllerResolverInterface $controller_resolver, Request $request, ModuleHandlerInterface $module_handler) {
- parent::__construct('Menu\LocalAction', $namespaces, array(), 'Drupal\Core\Annotation\Menu\LocalAction');
+ public function __construct(SearchableNamespacesInterface $root_namespaces, ControllerResolverInterface $controller_resolver, Request $request, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'Menu\LocalAction', array(), 'Drupal\Core\Annotation\Menu\LocalAction');
$this->controllerResolver = $controller_resolver;
$this->request = $request;
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 70db0b0..b9594c7 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -12,6 +12,7 @@
use Drupal\Core\Routing\RouteProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages discovery and instantiation of menu local task plugins.
@@ -53,9 +54,10 @@ class LocalTaskManager extends DefaultPluginManager {
/**
* Constructs a \Drupal\Core\Menu\LocalTaskManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface $controller_resolver
* An object to use in introspecting route methods.
* @param \Symfony\Component\HttpFoundation\Request $request
@@ -65,8 +67,8 @@ class LocalTaskManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.u
*/
- public function __construct(\Traversable $namespaces, ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler) {
- parent::__construct('Menu\LocalTask', $namespaces, array(), 'Drupal\Core\Annotation\Menu\LocalTask');
+ public function __construct(SearchableNamespacesInterface $root_namespaces, ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'Menu\LocalTask', array(), 'Drupal\Core\Annotation\Menu\LocalTask');
$this->controllerResolver = $controller_resolver;
$this->request = $request;
$this->routeProvider = $route_provider;
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
index 7a1cdac..ea61e6b 100644
--- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -18,6 +18,7 @@
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Base class for plugin managers.
@@ -60,13 +61,6 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
protected $alterHook;
/**
- * The plugin's subdirectory, for example views/filter.
- *
- * @var string
- */
- protected $subdir;
-
- /**
* The module handler to invoke the alter hook.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
@@ -81,13 +75,15 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
protected $languageManager;
/**
- * Creates the discovery object.
+ * Creates the DefaultPluginManager object.
*
- * @param string $subdir
- * The plugin's subdirectory, for example views/filter.
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
+ * @param string $namespace_suffix
+ * Suffix to build plugin namespaces from root namespaces, e.g. 'views\filter'.
+ * The resulting plugin namespace will be $root_namespace\Plugin\$namespace_suffix.
* @param array $annotation_namespaces
* (optional) The namespaces of classes that can be used as annotations.
* Defaults to an empty array.
@@ -95,9 +91,11 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
* (optional) The name of the annotation that contains the plugin definition.
* Defaults to 'Drupal\Component\Annotation\Plugin'.
*/
- public function __construct($subdir, \Traversable $namespaces, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
- $this->subdir = $subdir;
- $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $annotation_namespaces, $plugin_definition_annotation_name);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, $namespace_suffix, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, $namespace_suffix, $plugin_definition_annotation_name);
+ foreach ($annotation_namespaces as $namespace) {
+ $this->discovery->addAnnotationNamespace($namespace);
+ }
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->factory = new ContainerFactory($this);
}
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
index 6695db7..fd7c1fe 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
@@ -8,6 +8,7 @@
namespace Drupal\Core\Plugin\Discovery;
use Drupal\Component\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
@@ -15,51 +16,23 @@
class AnnotatedClassDiscovery extends ComponentAnnotatedClassDiscovery {
/**
- * The module name that defines the plugin type.
- *
- * @var string
- */
- protected $owner;
-
- /**
- * The plugin type, for example filter.
- *
- * @var string
- */
- protected $type;
-
- /**
- * An object containing the namespaces to look for plugin implementations.
- *
- * @var \Traversable
- */
- protected $rootNamespacesIterator;
-
- /**
* Constructs an AnnotatedClassDiscovery object.
*
- * @param string $subdir
- * The plugin's subdirectory, for example views/filter.
- * @param \Traversable $root_namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
- * \Plugin\$subdir will be appended to each namespace.
- * @param array $annotation_namespaces
- * (optional) The namespaces of classes that can be used as annotations.
- * Defaults to an empty array.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
+ * @param string $namespace_suffix
+ * Suffix to build plugin namespaces from root namespaces, e.g. 'views\filter'.
+ * The resulting plugin namespace will be $root_namespace\Plugin\$namespace_suffix.
* @param string $plugin_definition_annotation_name
* (optional) The name of the annotation that contains the plugin definition.
* Defaults to 'Drupal\Component\Annotation\Plugin'.
*/
- function __construct($subdir, \Traversable $root_namespaces, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
- $this->subdir = str_replace('/', '\\', $subdir);
- $this->rootNamespacesIterator = $root_namespaces;
- $annotation_namespaces += array(
- 'Drupal\Component\Annotation' => DRUPAL_ROOT . '/core/lib',
- 'Drupal\Core\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
- $plugin_namespaces = array();
- parent::__construct($plugin_namespaces, $annotation_namespaces, $plugin_definition_annotation_name);
+ function __construct(SearchableNamespacesInterface $root_namespaces, $namespace_suffix, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
+ parent::__construct($root_namespaces, 'Plugin\\' . $namespace_suffix, $plugin_definition_annotation_name);
+ $this->addAnnotationNamespace('Drupal\Component\Annotation');
+ $this->addAnnotationNamespace('Drupal\Core\Annotation');
}
/**
@@ -95,16 +68,4 @@ protected function getProviderFromNamespace($namespace) {
return NULL;
}
- /**
- * {@inheritdoc}
- */
- protected function getPluginNamespaces() {
- $plugin_namespaces = array();
- foreach ($this->rootNamespacesIterator as $namespace => $dir) {
- $plugin_namespaces["$namespace\\Plugin\\{$this->subdir}"] = array($dir);
- }
-
- return $plugin_namespaces;
- }
-
}
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index 5c48fb0..1608408 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -18,6 +18,7 @@
use Drupal\Core\Validation\DrupalTranslator;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\Validation;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages data type plugins.
@@ -45,14 +46,25 @@ class TypedDataManager extends DefaultPluginManager {
*/
protected $prototypes = array();
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ /**
+ * Overrides \Drupal\Core\Plugin\DefaultPluginManager::__construct().
+ *
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+ * Cache backend instance to use.
+ * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * The language manager.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler to invoke the alter hook with.
+ */
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
$this->alterInfo($module_handler, 'data_type_info');
$this->setCacheBackend($cache_backend, $language_manager, 'typed_data:types');
- $annotation_namespaces = array(
- 'Drupal\Core\TypedData\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
- parent::__construct('DataType', $namespaces, $annotation_namespaces, 'Drupal\Core\TypedData\Annotation\DataType');
+ parent::__construct($root_namespaces, 'DataType', array('Drupal\Core\TypedData\Annotation'), 'Drupal\Core\TypedData\Annotation\DataType');
}
/**
diff --git a/core/lib/Drupal/Core/Validation/ConstraintManager.php b/core/lib/Drupal/Core/Validation/ConstraintManager.php
index 1284978..9944e27 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintManager.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintManager.php
@@ -12,6 +12,7 @@
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Constraint plugin manager.
@@ -34,11 +35,12 @@
class ConstraintManager extends DefaultPluginManager {
/**
- * Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
+ * Overrides \Drupal\Core\Plugin\DefaultPluginManager::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
@@ -46,8 +48,8 @@ class ConstraintManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
- parent::__construct('Validation/Constraint', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'Validation\Constraint');
$this->discovery = new StaticDiscoveryDecorator($this->discovery, array($this, 'registerDefinitions'));
$this->alterInfo($module_handler, 'validation_constraint');
$this->setCacheBackend($cache_backend, $language_manager, 'validation_constraint');
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/AggregatorPluginManager.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/AggregatorPluginManager.php
index 2aa6731..24cd528 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/AggregatorPluginManager.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/AggregatorPluginManager.php
@@ -12,6 +12,7 @@
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages aggregator plugins.
@@ -23,22 +24,20 @@ class AggregatorPluginManager extends PluginManagerBase {
*
* @param string $type
* The plugin type, for example fetcher.
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct($type, \Traversable $namespaces) {
+ public function __construct($type, SearchableNamespacesInterface $root_namespaces) {
$type_annotations = array(
'fetcher' => 'Drupal\aggregator\Annotation\AggregatorFetcher',
'parser' => 'Drupal\aggregator\Annotation\AggregatorParser',
'processor' => 'Drupal\aggregator\Annotation\AggregatorProcessor',
);
- $annotation_namespaces = array(
- 'Drupal\aggregator\Annotation' => DRUPAL_ROOT . '/core/modules/aggregator/lib',
- );
-
- $this->discovery = new AnnotatedClassDiscovery("aggregator/$type", $namespaces, $annotation_namespaces, $type_annotations[$type]);
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, "aggregator\\$type", $type_annotations[$type]);
+ $this->discovery->addAnnotationNamespace('Drupal\aggregator\Annotation');
$this->discovery = new CacheDecorator($this->discovery, "aggregator_$type:" . language(Language::TYPE_INTERFACE)->id);
$this->factory = new DefaultFactory($this->discovery);
}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 3963262..c3f4872 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -10,6 +10,7 @@
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages discovery and instantiation of block plugins.
*
@@ -22,9 +23,10 @@ class BlockManager extends DefaultPluginManager {
/**
* Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
@@ -32,8 +34,8 @@ class BlockManager extends DefaultPluginManager {
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
- parent::__construct('Block', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ parent::__construct($root_namespaces, 'Block');
$this->alterInfo($module_handler, 'block');
$this->setCacheBackend($cache_backend, $language_manager, 'block_plugins');
}
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
index 3b1ad15..ca2568a 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
@@ -15,6 +15,7 @@
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\editor\Plugin\Core\Entity\Editor;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* CKEditor Plugin manager.
@@ -24,13 +25,14 @@ class CKEditorPluginManager extends PluginManagerBase {
/**
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $annotation_namespaces = array('Drupal\ckeditor\Annotation' => $namespaces['Drupal\ckeditor']);
- $this->discovery = new AnnotatedClassDiscovery('CKEditorPlugin', $namespaces, $annotation_namespaces, 'Drupal\ckeditor\Annotation\CKEditorPlugin');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'CKEditorPlugin', 'Drupal\ckeditor\Annotation\CKEditorPlugin');
+ $this->discovery->addAnnotationNamespace('Drupal\ckeditor\Annotation');
$this->discovery = new AlterDecorator($this->discovery, 'ckeditor_plugin_info');
$this->discovery = new CacheDecorator($this->discovery, 'ckeditor_plugin');
$this->factory = new DefaultFactory($this->discovery);
diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php b/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php
index f4c544b..6352898 100644
--- a/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php
+++ b/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Editor manager.
@@ -24,13 +25,14 @@ class InPlaceEditorManager extends PluginManagerBase {
/**
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $annotation_namespaces = array('Drupal\edit\Annotation' => $namespaces['Drupal\edit']);
- $this->discovery = new AnnotatedClassDiscovery('InPlaceEditor', $namespaces, $annotation_namespaces, 'Drupal\edit\Annotation\InPlaceEditor');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'InPlaceEditor', 'Drupal\edit\Annotation\InPlaceEditor');
+ $this->discovery->addAnnotationNamespace('Drupal\edit\Annotation');
$this->discovery = new AlterDecorator($this->discovery, 'edit_editor');
$this->discovery = new CacheDecorator($this->discovery, 'edit:editor');
$this->factory = new DefaultFactory($this->discovery);
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php b/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php
index 2d05b1a..c55320d 100644
--- a/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/EditorManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Configurable text editor manager.
@@ -22,13 +23,14 @@ class EditorManager extends PluginManagerBase {
/**
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $annotation_namespaces = array('Drupal\editor\Annotation' => $namespaces['Drupal\editor']);
- $this->discovery = new AnnotatedClassDiscovery('Editor', $namespaces, $annotation_namespaces, 'Drupal\editor\Annotation\Editor');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'Editor', 'Drupal\editor\Annotation\Editor');
+ $this->discovery->addAnnotationNamespace('Drupal\editor\Annotation');
$this->discovery = new AlterDecorator($this->discovery, 'editor_info');
$this->discovery = new CacheDecorator($this->discovery, 'editor');
$this->factory = new ContainerFactory($this->discovery);
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Type/SelectionPluginManager.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Type/SelectionPluginManager.php
index c5ecb8f..daeef2d 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Type/SelectionPluginManager.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Type/SelectionPluginManager.php
@@ -15,6 +15,7 @@
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\entity_reference\Plugin\Type\Selection\SelectionBroken;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin type manager for the Entity Reference Selection plugin.
@@ -24,12 +25,9 @@ class SelectionPluginManager extends DefaultPluginManager {
/**
* {@inheritdoc}
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
- $this->subdir = 'entity_reference/selection';
- $annotation_namespaces = array(
- 'Drupal\entity_reference\Annotation' => $namespaces['Drupal\entity_reference']
- );
- $this->discovery = new AnnotatedClassDiscovery($this->subdir, $namespaces, $annotation_namespaces, 'Drupal\entity_reference\Annotation\EntityReferenceSelection');
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'entity_reference\selection', 'Drupal\entity_reference\Annotation\EntityReferenceSelection');
+ $this->discovery->addAnnotationNamespace('Drupal\entity_reference\Annotation');
// We're not using the parent constructor because we use a different factory
// method and don't need the derivative discovery decorator.
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
index 6eb0c9a..6c30aed 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
@@ -17,6 +17,7 @@
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\field\Plugin\Core\Entity\FieldInstance;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin type manager for field formatters.
@@ -33,9 +34,10 @@ class FormatterPluginManager extends DefaultPluginManager {
/**
* Constructs a FormatterPluginManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -43,10 +45,9 @@ class FormatterPluginManager extends DefaultPluginManager {
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
- $annotation_namespaces = array('Drupal\field\Annotation' => $namespaces['Drupal\field']);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
- parent::__construct('field/formatter', $namespaces, $annotation_namespaces, 'Drupal\field\Annotation\FieldFormatter');
+ parent::__construct($root_namespaces, 'field\formatter', array('Drupal\field\Annotation'), 'Drupal\field\Annotation\FieldFormatter');
$this->setCacheBackend($cache_backend, $language_manager, 'field_formatter_types');
$this->alterInfo($module_handler, 'field_formatter_info');
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
index 673f4c1..aa90554 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
@@ -16,6 +16,7 @@
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin type manager for field widgets.
@@ -42,9 +43,10 @@ class WidgetPluginManager extends DefaultPluginManager {
/**
* Constructs a WidgetPluginManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -52,8 +54,8 @@ class WidgetPluginManager extends DefaultPluginManager {
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
- parent::__construct('field/widget', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LanguageManager $language_manager) {
+ parent::__construct($root_namespaces, 'field\widget');
$this->setCacheBackend($cache_backend, $language_manager, 'field_widget_types');
$this->alterInfo($module_handler, 'field_widget_info');
diff --git a/core/modules/filter/lib/Drupal/filter/FilterPluginManager.php b/core/modules/filter/lib/Drupal/filter/FilterPluginManager.php
index 881cdf7..1a76d6a 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterPluginManager.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterPluginManager.php
@@ -14,6 +14,7 @@
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages text processing filters.
@@ -25,13 +26,14 @@ class FilterPluginManager extends PluginManagerBase {
/**
* Constructs a FilterPluginManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $annotation_namespaces = array('Drupal\filter\Annotation' => $namespaces['Drupal\filter']);
- $this->discovery = new AnnotatedClassDiscovery('Filter', $namespaces, $annotation_namespaces, 'Drupal\filter\Annotation\Filter');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'Filter', 'Drupal\filter\Annotation\Filter');
+ $this->discovery->addAnnotationNamespace('Drupal\filter\Annotation');
$this->discovery = new AlterDecorator($this->discovery, 'filter_info');
$cache_key = 'filter_plugins:' . language(Language::TYPE_INTERFACE)->id;
$cache_tags = array('filter_formats' => TRUE);
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php b/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
index e22623f1..605af8d 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
@@ -12,6 +12,7 @@
use Drupal\Component\Plugin\Discovery\ProcessDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Component\Plugin\Factory\ReflectionFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Layout plugin manager.
@@ -25,13 +26,14 @@ class LayoutManager extends PluginManagerBase {
/**
* Overrides Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
// Create layout plugin derivatives from declaratively defined layouts.
- $this->discovery = new AnnotatedClassDiscovery('Layout', $namespaces);
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'Layout');
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/Type/ResourcePluginManager.php b/core/modules/rest/lib/Drupal/rest/Plugin/Type/ResourcePluginManager.php
index 6edea17..c6f3c96 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/Type/ResourcePluginManager.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/Type/ResourcePluginManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages discovery and instantiation of resource plugins.
@@ -22,13 +23,14 @@ class ResourcePluginManager extends PluginManagerBase {
/**
* Overrides Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
// Create resource plugin derivatives from declaratively defined resources.
- $this->discovery = new AnnotatedClassDiscovery('rest/resource', $namespaces);
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'rest\resource');
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'rest_resource');
$this->discovery = new CacheDecorator($this->discovery, 'rest');
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 587b6c0..57ac285 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -448,38 +448,24 @@ function simpletest_test_get_all() {
$groups = $cache->data;
}
else {
- // Select all PSR-0 classes in the Tests namespace of all modules.
- $classes = array();
+ // Assemble test namespaces for modules, themes and install profiles.
$module_data = system_rebuild_module_data();
$all_data = $module_data + system_rebuild_theme_data();
$all_data += drupal_system_listing('/\.profile$/', 'profiles', 'name');
+ $namespaces = array();
foreach ($all_data as $name => $data) {
- // Build directory in which the test files would reside.
- $tests_dir = DRUPAL_ROOT . '/' . dirname($data->uri) . '/lib/Drupal/' . $name . '/Tests';
- // Scan it for test files if it exists.
- if (is_dir($tests_dir)) {
- $files = file_scan_directory($tests_dir, '/.*\.php/');
- if (!empty($files)) {
- $basedir = DRUPAL_ROOT . '/' . dirname($data->uri) . '/lib/';
- foreach ($files as $file) {
- // Convert the file name into the namespaced class name.
- $replacements = array(
- '/' => '\\',
- $basedir => '',
- '.php' => '',
- );
- $classes[] = strtr($file->uri, $replacements);
- }
- }
- }
+ $namespaces[] = "Drupal\\$name\\Tests";
}
+ // Build a searchable namespace collection.
+ $namespaces = drupal_classloader()->buildSearchableNamespaces($namespaces);
+
// Check that each class has a getInfo() method and store the information
// in an array keyed with the group specified in the test information.
$groups = array();
- foreach ($classes as $class) {
+ foreach ($namespaces->discoverExistingClasses(TRUE) as $class) {
// Test classes need to implement getInfo() to be valid.
- if (class_exists($class) && method_exists($class, 'getInfo')) {
+ if (method_exists($class, 'getInfo')) {
$info = call_user_func(array($class, 'getInfo'));
// If this test class requires a non-existing module, skip it.
@@ -520,27 +506,19 @@ function simpletest_classloader_register() {
'theme' => array('dir' => 'themes', 'extension' => 'info'),
'profile' => array('dir' => 'profiles', 'extension' => 'profile'),
);
+ $loader_adapter = drupal_classloader();
foreach ($types as $type => $info) {
$matches = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.' . $info['extension'] . '$/', $info['dir']);
foreach ($matches as $name => $file) {
- drupal_classloader_register($name, dirname($file->uri));
- drupal_classloader()->addPrefix('Drupal\\' . $name . '\\Tests', DRUPAL_ROOT . '/' . dirname($file->uri) . '/tests');
+ $loader_adapter->addDrupalExtension($name, dirname($file->uri));
+ $loader_adapter->addDrupalExtensionTests($name, dirname($file->uri));
// While being there, prime drupal_get_filename().
drupal_get_filename($type, $name, $file->uri);
}
}
- // Register the core test directory so we can find \Drupal\UnitTestCase.
- drupal_classloader()->addPrefix('Drupal\\Tests', DRUPAL_ROOT . '/core/tests');
-
- // Manually register phpunit prefixes because they use a classmap instead of a
- // prefix. This can be safely removed if we move to using composer's
- // autoloader with a classmap.
- drupal_classloader()->addPrefixes(array(
- 'PHPUnit' => DRUPAL_ROOT . '/core/vendor/phpunit/phpunit',
- 'File_Iterator' => DRUPAL_ROOT . '/core/vendor/phpunit/php-file-iterator/',
- 'PHP_Timer' => DRUPAL_ROOT . '/core/vendor/phpunit/php-timer/',
- ));
+ // Register the core/tests directory so we can find Drupal\Tests\UnitTestCase.
+ $loader_adapter->addDrupalCoreTests();
}
/**
diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
index ddad9c6..fae135e 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
@@ -10,6 +10,7 @@
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages toolkit plugins.
@@ -19,16 +20,17 @@ class ImageToolkitManager extends DefaultPluginManager {
/**
* Constructs the ImageToolkitManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations.
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
- public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager) {
- parent::__construct('ImageToolkit', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager) {
+ parent::__construct($root_namespaces, 'ImageToolkit');
$this->setCacheBackend($cache_backend, $language_manager, 'image_toolkit');
}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Type/PluginUIManager.php b/core/modules/system/lib/Drupal/system/Plugin/Type/PluginUIManager.php
index 0514fe3..9bd09b3 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Type/PluginUIManager.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Type/PluginUIManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Manages discovery and instantiation of Plugin UI plugins.
@@ -24,12 +25,13 @@ class PluginUIManager extends PluginManagerBase {
/**
* Constructs a \Drupal\system\Plugin\Type\PluginUIManager object.
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $this->discovery = new AnnotatedClassDiscovery('PluginUI', $namespaces);
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'PluginUI');
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'plugin_ui');
$this->discovery = new CacheDecorator($this->discovery, 'plugin_ui');
diff --git a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
index db60d18..42baeb5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelTest.php
@@ -80,7 +80,7 @@ function testCompileDIC() {
// Test that our synthetic services are there.
$classloader = $container->get('class_loader');
$refClass = new ReflectionClass($classloader);
- $this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a classloader');
+ $this->assertTrue($refClass->hasMethod('addNamespacePSR0'), 'Container has a classloader registration tool.');
// We make this assertion here purely to show that the new container below
// is functioning correctly, i.e. we get a brand new ContainerBuilder
@@ -108,7 +108,8 @@ function testCompileDIC() {
// Test that our synthetic services are there.
$classloader = $container->get('class_loader');
$refClass = new ReflectionClass($classloader);
- $this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a classloader');
+ // @todo The signature of the registration tool needs to be finalized.
+ $this->assertTrue($refClass->hasMethod('addNamespacePSR0'), 'Container has a classloader registration tool.');
// Check that the location of the new module is registered.
$modules = $container->getParameter('container.modules');
$this->assertEqual($modules['service_provider_test'], drupal_get_filename('module', 'service_provider_test'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php
index 2fd8eb9..80dcecd 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php
@@ -44,6 +44,54 @@ function testClassLoading() {
}
/**
+ * Tests various edge cases with PSR-0.
+ *
+ * We do each test in a separate request, to make sure that the classes are
+ * not already loaded due to a previous test.
+ */
+ function testPSR0Specialties() {
+ // Enable the module_test and module_autoload_test modules.
+ module_enable(array('module_test', 'module_autoload_test'), FALSE);
+ $this->resetAll();
+
+ // Test that underscores in PSR-0 classes are dealt with correctly.
+ $this->drupalGet('module-test/class-loading/psr0-underscores');
+ $this->assertText('A class with underscores was found.',
+ 'Underscores in the class name are replaced with directory separators.');
+ $this->assertText('A file with underscores was not included.',
+ 'No file with underscores in the file name is included.');
+
+ // Test that the PSR-0 class loader does not include the same file twice.
+ $this->drupalGet('module-test/class-loading/psr0-multi-include');
+ $this->assertText('The application did not crash.',
+ 'The class loader avoids multiple file inclusion, if two PSR-0 classes are expected to be in the same file.');
+
+ // Test that no classes from the wrong module are included.
+ $this->drupalGet('module-test/class-loading/psr0-prefix-clash');
+ $this->assertText('A file was not included because it is in the wrong folder.',
+ 'A PSR-0 class loader will not look in the lib folder of another module.');
+ }
+
+ /**
+ * Tests PSR-X class loading for modules.
+ * PSR-X classes are in the src/ folder of a module.
+ */
+ function testClassLoadingPSRX() {
+ // Enable the module_test and module_autoload_test modules.
+ module_enable(array('module_test', 'module_autoload_test'), FALSE);
+ $this->resetAll();
+
+ // Check that PSR-X classes are found.
+ $this->drupalGet('module-test/class-loading/psrx');
+ $this->assertText('SomeClassPSRX was found.',
+ 'Classes are found by the PSR-X class loader.');
+ $this->assertText('ClassWith_Underscore_PSRX was found.',
+ 'Classes with underscores are found by the PSR-X class loader.');
+ $this->assertText('Class in sub-namespace was found.',
+ 'Classes in sub-namespaces are found by the PSR-X class loader.');
+ }
+
+ /**
* Tests that module-provided classes can't be loaded from disabled modules.
*
* @see \Drupal\module_autoload_test\SomeClass
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
index 5f8ee2d..8e5a3b7 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/AnnotatedClassDiscoveryTest.php
@@ -7,6 +7,7 @@
namespace Drupal\system\Tests\Plugin\Discovery;
+use Drupal\Core\ClassLoader\NamespaceInspectorAdapter;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
/**
@@ -57,9 +58,18 @@ public function setUp() {
'provider' => 'plugin_test',
),
);
- $namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
- $this->discovery = new AnnotatedClassDiscovery('plugin_test/fruit', $namespaces);
- $this->emptyDiscovery = new AnnotatedClassDiscovery('non_existing_module/non_existing_plugin_type', $namespaces);
+
+ // Build namespace inspector.
+ $adapter = NamespaceInspectorAdapter::start();
+ $adapter->addDrupalExtension('plugin_test', 'core/modules/system/tests/modules/plugin_test');
+ $adapter->addDrupalCore();
+
+ // Build searchable base namespaces.
+ $root_namespaces = $adapter->buildSearchableNamespaces(array('Drupal\plugin_test'));
+
+ // Build annotated class discovery.
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'plugin_test\fruit');
+ $this->emptyDiscovery = new AnnotatedClassDiscovery($root_namespaces, 'non_existing_module\non_existing_plugin_type');
}
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
index cbf2a16..65f0847 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/Discovery/CustomAnnotationClassDiscoveryTest.php
@@ -8,6 +8,7 @@
namespace Drupal\system\Tests\Plugin\Discovery;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\ClassLoader\NamespaceInspectorAdapter;
/**
* Tests that a custom annotation class is used.
@@ -41,13 +42,20 @@ protected function setUp() {
'provider' => 'plugin_test',
),
);
- $root_namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
- $annotation_namespaces = array(
- 'Drupal\plugin_test\Plugin\Annotation' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib',
- );
- $this->discovery = new AnnotatedClassDiscovery('plugin_test/custom_annotation', $root_namespaces, $annotation_namespaces, 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
- $this->emptyDiscovery = new AnnotatedClassDiscovery('non_existing_module/non_existing_plugin_type', $root_namespaces, $annotation_namespaces, 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
+ // Build namespace inspector.
+ $adapter = NamespaceInspectorAdapter::start();
+ $adapter->addDrupalExtension('plugin_test', 'core/modules/system/tests/modules/plugin_test');
+ $adapter->addDrupalCore();
+
+ // Build searchable namespaces.
+ $root_namespaces = $adapter->buildSearchableNamespaces(array('Drupal\plugin_test'));
+
+ // Build annotated class discovery.
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'plugin_test\custom_annotation', 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
+ $this->discovery->addAnnotationNamespace('Drupal\plugin_test\Plugin\Annotation');
+ $this->emptyDiscovery = new AnnotatedClassDiscovery($root_namespaces, 'non_existing_module\non_existing_plugin_type', 'Drupal\plugin_test\Plugin\Annotation\PluginExample');
+ $this->emptyDiscovery->addAnnotationNamespace('Drupal\plugin_test\Plugin\Annotation');
}
}
diff --git a/core/modules/system/tests/modules/module_autoload_test/lib/Drupal/module_autoload_test/ExistingClass/WithUnderscore.php b/core/modules/system/tests/modules/module_autoload_test/lib/Drupal/module_autoload_test/ExistingClass/WithUnderscore.php
new file mode 100644
index 0000000..dda4756
--- /dev/null
+++ b/core/modules/system/tests/modules/module_autoload_test/lib/Drupal/module_autoload_test/ExistingClass/WithUnderscore.php
@@ -0,0 +1,10 @@
+ 'module_test_class_loading',
'access callback' => TRUE,
);
+ $items['module-test/class-loading/psr0-underscores'] = array(
+ 'title' => 'Test PSR-0 underscore handling',
+ 'page callback' => 'module_test_class_loading_psr0_underscores',
+ 'access callback' => TRUE,
+ );
+ $items['module-test/class-loading/psr0-multi-include'] = array(
+ 'title' => 'Test PSR-0 multi includes',
+ 'page callback' => 'module_test_class_loading_psr0_multi_include',
+ 'access callback' => TRUE,
+ );
+ $items['module-test/class-loading/psr0-prefix-clash'] = array(
+ 'title' => 'Test PSR-0 prefix clash',
+ 'page callback' => 'module_test_class_loading_psr0_prefix_clash',
+ 'access callback' => TRUE,
+ );
+ $items['module-test/class-loading/psrx'] = array(
+ 'title' => 'Test PSR-X class loading',
+ 'page callback' => 'module_test_class_loading_psrx',
+ 'access callback' => TRUE,
+ );
return $items;
}
@@ -150,6 +170,58 @@ function module_test_class_loading() {
}
/**
+ * Page callback for 'module-test/class-loading/psr0-underscores'.
+ */
+function module_test_class_loading_psr0_underscores() {
+ $pieces = array();
+ if (class_exists('Drupal\module_autoload_test\ExistingClass_WithUnderscore')) {
+ $pieces[] = 'A class with underscores was found.';
+ }
+ if (!class_exists('Drupal\module_autoload_test\UnloadableClass_WithUnderscore')) {
+ $pieces[] = 'A file with underscores was not included.';
+ }
+ return implode('
', array_filter($pieces));
+}
+
+/**
+ * Page callback for 'module-test/class-loading/psr0-multi-include'.
+ */
+function module_test_class_loading_psr0_multi_include() {
+ class_exists('Drupal\module_autoload_test\SubNamespace\SomeClass');
+ class_exists('Drupal\module_autoload_test\SubNamespace_SomeClass');
+ // If we get here, the application did not crash.
+ return 'The application did not crash.';
+}
+
+/**
+ * Page callback for 'module-test/class-loading/psr0-prefix-clash'.
+ */
+function module_test_class_loading_psr0_prefix_clash() {
+ // The class is defined in the lib folder of module_autoload_test, but we
+ // expect the class loader to ignore that file.
+ if (!class_exists('Drupal\module_autoload_test_subnamespace\PrefixTestClass')) {
+ return 'A file was not included because it is in the wrong folder.';
+ }
+}
+
+/**
+ * Page callback for 'module-test/class-loading/psrx'.
+ */
+function module_test_class_loading_psrx() {
+ $pieces = array();
+ if (class_exists('Drupal\module_autoload_test\SomeClassPSRX')) {
+ $pieces[] = 'SomeClassPSRX was found.';
+ }
+ if (class_exists('Drupal\module_autoload_test\ClassWith_Underscore_PSRX')) {
+ $pieces[] = 'ClassWith_Underscore_PSRX was found.';
+ }
+ if (class_exists('Drupal\module_autoload_test\SubNamespacePSRX\SomeClass')) {
+ $pieces[] = 'Class in sub-namespace was found.';
+ }
+ return implode('
', array_filter($pieces));
+}
+
+/**
* Implements hook_modules_enabled().
*/
function module_test_modules_enabled($modules) {
diff --git a/core/modules/tour/lib/Drupal/tour/TipPluginManager.php b/core/modules/tour/lib/Drupal/tour/TipPluginManager.php
index e23669b..607bd91 100644
--- a/core/modules/tour/lib/Drupal/tour/TipPluginManager.php
+++ b/core/modules/tour/lib/Drupal/tour/TipPluginManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Configurable tour manager.
@@ -22,13 +23,14 @@ class TipPluginManager extends PluginManagerBase {
/**
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
*
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct(\Traversable $namespaces) {
- $annotation_namespaces = array('Drupal\tour\Annotation' => $namespaces['Drupal\tour']);
- $this->discovery = new AnnotatedClassDiscovery('tour/tip', $namespaces, $annotation_namespaces, 'Drupal\tour\Annotation\Tip');
+ public function __construct(SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'tour\tip', 'Drupal\tour\Annotation\Tip');
+ $this->discovery->addAnnotationNamespace('Drupal\tour\Annotation');
$this->discovery = new AlterDecorator($this->discovery, 'tour_tips_info');
$this->discovery = new CacheDecorator($this->discovery, 'tour');
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Discovery/ViewsHandlerDiscovery.php b/core/modules/views/lib/Drupal/views/Plugin/Discovery/ViewsHandlerDiscovery.php
index 460ef5a..dec494c 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Discovery/ViewsHandlerDiscovery.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Discovery/ViewsHandlerDiscovery.php
@@ -7,12 +7,14 @@
namespace Drupal\views\Plugin\Discovery;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery as CoreAnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Defines a discovery mechanism to find Views handlers in PSR-0 namespaces.
*/
-class ViewsHandlerDiscovery extends AnnotatedClassDiscovery {
+class ViewsHandlerDiscovery extends CoreAnnotatedClassDiscovery {
/**
* The type of handler being discovered.
@@ -22,60 +24,31 @@ class ViewsHandlerDiscovery extends AnnotatedClassDiscovery {
protected $type;
/**
- * An object containing the namespaces to look for plugin implementations.
- *
- * @var \Traversable
- */
- protected $rootNamespacesIterator;
-
- /**
* Constructs a ViewsHandlerDiscovery object.
*
* @param string $type
* The plugin type, for example filter.
- * @param \Traversable $root_namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- function __construct($type, \Traversable $root_namespaces) {
+ function __construct($type, SearchableNamespacesInterface $root_namespaces) {
$this->type = $type;
- $this->rootNamespacesIterator = $root_namespaces;
-
- $annotation_namespaces = array(
- 'Drupal\Component\Annotation' => DRUPAL_ROOT . '/core/lib',
- );
- $plugin_namespaces = array();
- foreach ($root_namespaces as $namespace => $dir) {
- $plugin_namespaces["$namespace\\Plugin\\views\\{$type}"] = array($dir);
- }
-
- $this->pluginNamespaces = $plugin_namespaces;
- $this->annotationNamespaces = $annotation_namespaces;
- $this->pluginDefinitionAnnotationName = 'Drupal\Component\Annotation\PluginID';
+ ComponentAnnotatedClassDiscovery::__construct($root_namespaces, 'views\\' . $type, 'Drupal\Component\Annotation\PluginID');
+ $this->addAnnotationNamespace('Drupal\Component\Annotation');
}
/**
* {@inheritdoc}
*/
public function getDefinitions() {
- // Add the plugin_type to the definition.
$definitions = parent::getDefinitions();
+ // Add the plugin_type to each definition.
foreach ($definitions as $key => $definition) {
$definitions[$key]['plugin_type'] = $this->type;
}
return $definitions;
}
- /**
- * {@inheritdoc}
- */
- protected function getPluginNamespaces() {
- $plugin_namespaces = array();
- foreach ($this->rootNamespacesIterator as $namespace => $dir) {
- $plugin_namespaces["$namespace\\Plugin\\views\\{$this->type}"] = array($dir);
- }
-
- return $plugin_namespaces;
- }
-
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
index 4ac2fac..067b11f 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
@@ -13,6 +13,7 @@
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\views\Plugin\Discovery\ViewsHandlerDiscovery;
use Drupal\views\ViewsData;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin type manager for all views handlers.
@@ -46,7 +47,7 @@ class ViewsHandlerManager extends PluginManagerBase {
* @param \Drupal\views\ViewsData $views_data
* The views data cache.
*/
- public function __construct($handler_type, \Traversable $namespaces, ViewsData $views_data) {
+ public function __construct($handler_type, SearchableNamespacesInterface $namespaces, ViewsData $views_data) {
$this->discovery = new ViewsHandlerDiscovery($handler_type, $namespaces);
$this->discovery = new CacheDecorator($this->discovery, "views:$handler_type", 'views_info');
diff --git a/core/modules/views/lib/Drupal/views/Plugin/ViewsPluginManager.php b/core/modules/views/lib/Drupal/views/Plugin/ViewsPluginManager.php
index 2b8c6a6..7afddbc 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/ViewsPluginManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/ViewsPluginManager.php
@@ -15,6 +15,7 @@
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\ClassLoader\SearchableNamespacesInterface;
/**
* Plugin type manager for all views plugins.
@@ -26,12 +27,13 @@ class ViewsPluginManager extends PluginManagerBase {
*
* @param string $type
* The plugin type, for example filter.
- * @param \Traversable $namespaces
- * An object that implements \Traversable which contains the root paths
- * keyed by the corresponding namespace to look for plugin implementations,
+ * @param SearchableNamespacesInterface $root_namespaces
+ * Searchable namespaces for enabled extensions and core.
+ * This will be used to build the plugin namespaces by adding the suffix.
+ * E.g. the root namespace for a module is Drupal\$module.
*/
- public function __construct($type, \Traversable $namespaces) {
- $this->discovery = new AnnotatedClassDiscovery("views/$type", $namespaces);
+ public function __construct($type, SearchableNamespacesInterface $root_namespaces) {
+ $this->discovery = new AnnotatedClassDiscovery($root_namespaces, "views\\$type");
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
$this->discovery = new AlterDecorator($this->discovery, 'views_plugins_' . $type);
diff --git a/core/scripts/switch-psr4.sh b/core/scripts/switch-psr4.sh
new file mode 100644
index 0000000..3cec824
--- /dev/null
+++ b/core/scripts/switch-psr4.sh
@@ -0,0 +1,108 @@
+#!/bin/php
+isDot()) {
+ // do nothing
+ }
+ elseif ($fileinfo->isDir()) {
+ process_candidate_dir($fileinfo->getPathname());
+ }
+ }
+}
+
+function process_candidate_dir($dir) {
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ if ($fileinfo->isDot()) {
+ // Ignore "." and "..".
+ }
+ elseif ($fileinfo->isDir()) {
+ // It's a directory.
+ switch ($fileinfo->getFilename()) {
+ case 'lib':
+ case 'src':
+ case 'module_autoload_test':
+ // Ignore these directory names.
+ continue;
+ default:
+ // Look for more extensions in subdirectories.
+ process_candidate_dir($fileinfo->getPathname());
+ }
+ }
+ else {
+ // It's a file.
+ if (preg_match('/^(.+).info.yml$/', $fileinfo->getFilename(), $m)) {
+ // It's a *.info.yml file, so we found an extension directory.
+ $extension_name = $m[1];
+ }
+ }
+ }
+ if (isset($extension_name)) {
+ process_extension($extension_name, $dir);
+ }
+}
+
+function process_extension($name, $dir) {
+
+ // Move main module class files.
+ if (is_dir("$dir/lib/Drupal/$name")) {
+ // This is a module directory with a PSR-0 /lib/ folder.
+ if (!is_dir($dir . '/src')) {
+ mkdir($dir . '/src');
+ }
+ rename("$dir/lib/Drupal/$name", "$dir/src");
+ }
+
+ // Move class files in tests directory.
+ if (is_dir("$dir/tests/Drupal/$name/Tests")) {
+ rename("$dir/tests/Drupal/$name/Tests", "$dir/tests/src");
+ }
+
+ // Clean up empty directories.
+ foreach (array(
+ "lib/Drupal/$name",
+ 'lib/Drupal',
+ 'lib',
+ "tests/Drupal/$name/Tests",
+ "tests/Drupal/$name",
+ "tests/Drupal",
+ ) as $subdir) {
+ if (is_dir_empty("$dir/$subdir")) {
+ rmdir("$dir/$subdir");
+ }
+ }
+}
+
+function is_dir_empty($dir) {
+ if (!is_readable($dir)) {
+ return NULL;
+ }
+ $handle = opendir($dir);
+ while (false !== ($entry = readdir($handle))) {
+ if ($entry != "." && $entry != "..") {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
diff --git a/core/vendor/autoload.php b/core/vendor/autoload.php
index 51fea2c..2a887f8 100644
--- a/core/vendor/autoload.php
+++ b/core/vendor/autoload.php
@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
-return ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37::getLoader();
+return ComposerAutoloaderInit6b1785896dc208c3c153c7ce6a3ee061::getLoader();
diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php
index 87cf570..4b26c8a 100644
--- a/core/vendor/composer/autoload_namespaces.php
+++ b/core/vendor/composer/autoload_namespaces.php
@@ -24,6 +24,7 @@
'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'),
'Symfony\\Cmf\\Component\\Routing' => array($vendorDir . '/symfony-cmf/routing'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
+ 'Krautoload\\' => array($vendorDir . '/donquixote/krautoload/src'),
'Guzzle\\Stream' => array($vendorDir . '/guzzle/stream'),
'Guzzle\\Parser' => array($vendorDir . '/guzzle/parser'),
'Guzzle\\Http' => array($vendorDir . '/guzzle/http'),
diff --git a/core/vendor/composer/autoload_real.php b/core/vendor/composer/autoload_real.php
index 7d1d4ad..86fb01b 100644
--- a/core/vendor/composer/autoload_real.php
+++ b/core/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php generated by Composer
-class ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37
+class ComposerAutoloaderInit6b1785896dc208c3c153c7ce6a3ee061
{
private static $loader;
@@ -19,9 +19,9 @@ public static function getLoader()
return self::$loader;
}
- spl_autoload_register(array('ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit6b1785896dc208c3c153c7ce6a3ee061', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
- spl_autoload_unregister(array('ComposerAutoloaderInit4ae4005bb4ec82f3372265feb7e84f37', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit6b1785896dc208c3c153c7ce6a3ee061', 'loadClassLoader'));
$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index 322247d..433d493 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -1731,5 +1731,59 @@
"feed",
"zf2"
]
+ },
+ {
+ "name": "donquixote/krautoload",
+ "version": "0.0.1-alpha7",
+ "version_normalized": "0.0.1.0-alpha7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/donquixote/krautoload.git",
+ "reference": "0.0.1-alpha7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/donquixote/krautoload/zipball/0.0.1-alpha7",
+ "reference": "0.0.1-alpha7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/php-invoker": ">=1.1.2",
+ "phpunit/phpunit": ">=3.7"
+ },
+ "time": "2013-07-18 21:43:11",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Krautoload\\": "src/"
+ }
+ },
+ "license": [
+ "GPL"
+ ],
+ "authors": [
+ {
+ "name": "Andreas Hennings",
+ "homepage": "http://github.com/donquixote"
+ }
+ ],
+ "description": "Krautoload is a pluggable class loader and class discovery tool.",
+ "homepage": "http://github.com/donquixote/krautoload",
+ "keywords": [
+ "PEAR",
+ "PSR-0",
+ "PSR-4",
+ "PSR-X",
+ "autoload",
+ "classloader"
+ ],
+ "support": {
+ "issues": "http://github.com/donquixote/krautoload/issues",
+ "source": "https://github.com/donquixote/krautoload/tree/0.0.1-alpha7"
+ }
}
]
diff --git a/core/vendor/donquixote/krautoload/.gitignore b/core/vendor/donquixote/krautoload/.gitignore
new file mode 100644
index 0000000..188d532
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/.gitignore
@@ -0,0 +1,4 @@
+clover.xml
+composer.lock
+vendor
+.idea
diff --git a/core/vendor/donquixote/krautoload/.travis.yml b/core/vendor/donquixote/krautoload/.travis.yml
new file mode 100644
index 0000000..8a8746d
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/.travis.yml
@@ -0,0 +1,14 @@
+language: php
+
+php:
+ - 5.3.3
+ - 5.3
+ - 5.4
+ - 5.5
+
+before_script:
+ - composer install --dev --prefer-source
+
+script:
+ - vendor/bin/phpunit --coverage-clover clover.xml
+ - php coverage-checker.php clover.xml 95
diff --git a/core/vendor/donquixote/krautoload/LICENSE b/core/vendor/donquixote/krautoload/LICENSE
new file mode 100644
index 0000000..9b3e7af
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Andreas Hennings
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/core/vendor/donquixote/krautoload/README.md b/core/vendor/donquixote/krautoload/README.md
new file mode 100644
index 0000000..5106eb4
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/README.md
@@ -0,0 +1,136 @@
+[![Build Status](https://secure.travis-ci.org/donquixote/krautoload.png)](https://travis-ci.org/donquixote/krautoload)
+
+Krautoload is a pluggable PHP class autoloader library.
+In addition, it can do class discovery based on the same mappings registered in the class loader.
+
+The class loader has native support for
+- Class maps.
+- The [proposed PSR-X](https://github.com/php-fig/fig-standards/blob/master/proposed/autoloader.md), which is a shallow-dir variation of PSR-0 without the special underscore handling.
+- [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)
+- PEAR (that is the old-school pattern with underscores instead of namespaces)
+ (yes, this is just a subset of PSR-0, but Krautoload has explicit support for it)
+- Variations of PSR-0 with different levels of "safety" (to avoid duplicate file inclusion, etc)
+
+It also supports some "non-standard" stuff, *just because we can*, and it was too tempting not to do it:
+- Variation of PSR-0 which allows shallow directory structures.
+- Variation of PEAR which allows shallow directory structures.
+
+Besides that, custom plugins can be mapped to any namespaces and prefixes, to allow the most wonky logical mappings.
+E.g. there is an example plugin "CamelSwap", that would map a class ".._TinyPetShop" to "../shop/pet/tiny.php".
+(the idea is to support old-school libraries which still have *some logic* in where they put their classes)
+
+
+### Performance
+
+The basic Krautoload "pluggable" class loader is designed to have a decent performance, that does no have to be afraid of competition.
+Especially, the main lookup algorithm is designed to perform equally well no matter how many namespaces are registered.
+(even if most of these namespaces all share the same prefix)
+
+If that is not enough, there are different cache decorators, mostly equivalent with those you find in Symfony2:
+- APC cache
+- XCache
+- WinCache
+- Generated class maps
+ - Note: That's not a decorator, but can still speed you up.
+ - Krautoload can't generate its own class maps, but there are enough tools out there which can.
+
+
+## Project status and history
+
+The project has changed a lot in recent days and weeks, but it is now probably quite close to a stable shape.
+Still, some API details may still change based on community feedback.
+Especially, the term "PSR-X" may change in the future, if it gets accepted.
+
+The project is a spin-off of the ["xautoload" module for Drupal](http://drupal.org/project/xautoload), with some changes.
+
+Unlike xautoload, Krautoload is written in anticipation of the hopefully upcoming PSR-X.
+It is optimized for PSR-X, and needs a tiny-tiny extra operation if wired up with PSR-0, for the special underscore handling.
+
+
+## Purpose / Audience
+
+Modern PHP projects typically use class loading solutions shipped with the framework, or provided by Composer.
+Thus, Krautoload is mainly aimed at framework developers, for full inclusion, copying, or inspiration.
+
+
+## Usage
+
+Krautoload provides a start-off class with static methods, for those who want to avoid a lengthy bootstrap.
+Alternative bootstrap helpers may be provided based on community feedback.
+
+```php
+require_once "$path_to_krautoload/src/Krautoload.php";
+
+// Create the class loader and register it.
+$krautoload = Krautoload::start();
+
+// Register additional namespaces
+$krautoload->addNamespacePSR0('FooVendor\FooPackage', "$path_to_foo_package/src");
+
+new FooVendor\FooPackage\Foo\Bar\Baz();
+```
+
+See [Krautoload\RegistrationHub](https://github.com/donquixote/krautoload/blob/master/src/Krautoload/RegistrationHub.php)
+to see all the available registration methods.
+
+
+### Usage with Composer
+
+Krautoload can be used instead of the autoload.php generated by Composer.
+Boot Krautoload like above, and then
+
+```php
+// Let Krautoload look for the files defining the namespace map and class map.
+$krautoload->composerVendorDir($vendor_dir);
+```
+
+
+### Class discovery
+
+You need
+- a "NamespaceInspector" object (which is a more powerful version of the ClassLoader)
+- a "SearchableNamespaces" object, using the namespace inspector.
+- Then you can do class discovery within those namespaces.
+
+```php
+// Start Krautoload with discovery capabilities.
+// This means, it will create a NamespaceInspector instead of a ClassLoader.
+// The only overhead this adds is *two* additional files being loaded (one class, one interface).
+// So, no reason not to.
+$krautoload = Krautoload::start(array('introspection' => TRUE));
+// Register your stuff
+$krautoload->addPrefix...
+$krautoload->addNamespace...
+// Class loading should work now.
+new MyVendor\MyPackage\Foo\Bar();
+// Create searchable namespaces object.
+$searchableNamespaces = $krautoload->buildSearchableNamespaces(array(
+ 'MyVendor\MyPackage\Foo1',
+ 'MyVendor\MyPackage\Foo2',
+));
+// Scan those namespaces
+$recursive = TRUE;
+$classes = $searchableNamespaces->discoverExistingClasses($recursive);
+```
+
+
+## Unit tests
+
+Tests exist, but coverage is still not fully acceptable. This is why Travis complains.
+https://travis-ci.org/donquixote/krautoload
+
+Any help is appreciated.
+
+
+## Benchmarks
+
+Benchmarks would be nice to have, but they do not exist yet. Any help
+appreciated.
+
+Like Tests, benchmarks *can* be programmed with a mocked-out filesystem, where
+instead of actually doing file inclusion or file_exists(), we simply count the
+number of times this would happen.
+
+This will not tell us the real duration in a live environment, but it will
+determine the time used for the actual class finding much more accurately than
+with the natural variations of filesystem operations.
diff --git a/core/vendor/donquixote/krautoload/composer.json b/core/vendor/donquixote/krautoload/composer.json
new file mode 100644
index 0000000..d793c10
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "donquixote/krautoload",
+ "description": "Krautoload is a pluggable class loader and class discovery tool.",
+ "keywords": ["autoload", "classloader", "PSR-0", "PSR-4", "PSR-X", "PEAR"],
+ "homepage": "http://github.com/donquixote/krautoload",
+ "license": "GPL",
+ "authors": [
+ {
+ "name": "Andreas Hennings",
+ "homepage": "http://github.com/donquixote"
+ }
+ ],
+ "support": {
+ "issues": "http://github.com/donquixote/krautoload/issues"
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/php-invoker": ">=1.1.2",
+ "phpunit/phpunit": ">=3.7"
+ },
+ "autoload": {
+ "psr-0": {
+ "Krautoload\\": "src/"
+ }
+ },
+ "minimum-stability": "alpha"
+}
diff --git a/core/vendor/donquixote/krautoload/coverage-checker.php b/core/vendor/donquixote/krautoload/coverage-checker.php
new file mode 100644
index 0000000..4efe93c
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/coverage-checker.php
@@ -0,0 +1,42 @@
+xpath('//metrics');
+
+$totalElements = 0;
+$checkedElements = 0;
+
+foreach ($metrics as $metric) {
+ $totalElements += (int)$metric['elements'];
+ $checkedElements += (int)$metric['coveredelements'];
+}
+
+$coverage = round(($checkedElements / $totalElements) * 100);
+
+if ($coverage < $percentage) {
+ printf(
+ 'Code coverage is %f%%, which is below the accepted %f%%' . PHP_EOL,
+ $coverage, $percentage
+ );
+ exit(1);
+}
+
+printf('Code coverage is %f%% - OK!' . PHP_EOL, $coverage);
diff --git a/core/vendor/donquixote/krautoload/phpunit.xml.dist b/core/vendor/donquixote/krautoload/phpunit.xml.dist
new file mode 100644
index 0000000..0e5d119
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/phpunit.xml.dist
@@ -0,0 +1,15 @@
+
+
+
+
+
+ ./tests/src/
+
+
+
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload.php b/core/vendor/donquixote/krautoload/src/Krautoload.php
new file mode 100644
index 0000000..78308bf
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload.php
@@ -0,0 +1,110 @@
+ FALSE,
+ 'cache_prefix' => NULL,
+ 'introspection' => FALSE,
+ );
+
+ // Include the bare minimum we need before Krautoload can load its own.
+ $basedir = dirname(__FILE__) . '/Krautoload';
+ require_once $basedir . '/ClassLoader/Interface.php';
+ require_once $basedir . '/ClassLoader/Abstract.php';
+ require_once $basedir . '/ClassLoader/Pluggable/Interface.php';
+ require_once $basedir . '/ClassLoader/Pluggable.php';
+ require_once $basedir . '/NamespacePathPlugin/Interface.php';
+ require_once $basedir . '/NamespacePathPlugin/ShallowPSR0.php';
+ require_once $basedir . '/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php';
+
+ // Build the class loader.
+ if (!empty($options['introspection'])) {
+ // Build a fancy class loader that can also do class discovery.
+ // This can be useful to reuse the registered path-namespace mappings for
+ // class discovery.
+ // This being said, it is always possible to create a NamespaceInspector
+ // independently of the actively registered class loader.
+ require_once $basedir . '/NamespaceInspector/Interface.php';
+ require_once $basedir . '/NamespaceInspector/Pluggable/Interface.php';
+ require_once $basedir . '/NamespaceInspector/Pluggable.php';
+ $loader = new Krautoload\NamespaceInspector_Pluggable();
+ }
+ else {
+ // Build a basic class loader, that can only do class loading.
+ $loader = new Krautoload\ClassLoader_Pluggable();
+ }
+
+ // Wire up the class finder so it can find Krautoload classes.
+ // Krautoload uses PSR-0 with only underscores after the package namespace.
+ $plugin = new Krautoload\NamespacePathPlugin_ShallowPSR0_AllUnderscore();
+ $loader->addNamespacePlugin('Krautoload' . DIRECTORY_SEPARATOR, $basedir . DIRECTORY_SEPARATOR, $plugin);
+
+ // Register the loader to the spl stack.
+ $loader->register();
+
+ // Create the adapter.
+ if (!empty($options['introspection'])) {
+ $adapter = new Krautoload\Adapter_NamespaceInspector_Pluggable($loader);
+ }
+ else {
+ $adapter = new Krautoload\Adapter_ClassLoader_Pluggable($loader);
+ }
+
+ // Enable the cache, if any.
+ switch ($options['cache']) {
+ case 'ApcCache':
+ case 'XCache':
+ case 'WinCache':
+ if (isset($options['cache_prefix'])) {
+ // Load one more class that we will need.
+ require_once $basedir . '/InjectedAPI/ClassFinder/LoadClassGetFile.php';
+ // Build the cache decorator object.
+ $cachedLoaderClass = 'Krautoload\ClassLoader_Cached_' . $options['cache'];
+ /**
+ * @var \Krautoload\ClassLoader_Interface $cachedLoader
+ */
+ $cachedLoader = new $cachedLoaderClass($loader, $options['cache_prefix']);
+ // Replace the loader on the spl stack.
+ $loader->unregister();
+ $cachedLoader->register();
+ // @todo Add the cached loader to the adapter to make it accessible to the world?
+ }
+ }
+
+ self::$adapter = $adapter;
+ return $adapter;
+ }
+
+ /**
+ * Gets the $adapter object, if exists.
+ *
+ * @return \Krautoload\Adapter_ClassLoader_Interface
+ * @throws Exception
+ */
+ static function registration() {
+ if (!isset(self::$adapter)) {
+ throw new Exception("Krautoload::start() must run before Krautoload::registration()");
+ }
+ return self::$adapter;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/ClassLoader/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/ClassLoader/Interface.php
new file mode 100644
index 0000000..8e47a5d
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/ClassLoader/Interface.php
@@ -0,0 +1,228 @@
+finder = $finder;
+ $this->plugins['ShallowPEAR'] = new PrefixPathPlugin_ShallowPEAR();
+ $this->plugins['ShallowPEAR_Uncertain'] = new PrefixPathPlugin_ShallowPEAR_Uncertain();
+ $this->plugins['ShallowPSR0'] = new NamespacePathPlugin_ShallowPSR0();
+ $this->plugins['PSRX'] = new NamespacePathPlugin_PSRX();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getFinder() {
+ return $this->finder;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function krautoloadCallback($callback) {
+ call_user_func($callback, $this);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function krautoloadFile($file) {
+ $callback = require $file;
+ call_user_func($callback, $this);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function composerVendorDir($dir) {
+ if (is_file($dir . '/composer/autoload_namespaces.php')) {
+ $namespaces = include $dir . '/composer/autoload_namespaces.php';
+ $this->addPrefixesPSR0($namespaces);
+ }
+ if (is_file($dir . '/composer/autoload_classmap.php')) {
+ $class_map = include $dir . '/composer/autoload_classmap.php';
+ $this->addClassMap($class_map, FALSE);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixesPSR0(array $prefixes) {
+ foreach ($prefixes as $prefix => $rootDirs) {
+ $this->addPrefixPSR0($prefix, $rootDirs);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixPSR0($prefix, $rootDirs) {
+
+ if ('' === $prefix) {
+ // We consider this as a "fallback".
+ $this->addNamespacePSR0('', $rootDirs);
+ $this->addPrefixPEAR('', $rootDirs, TRUE);
+ }
+ elseif ('\\' === substr($prefix, -1)) {
+ // We know that $prefix is meant as a namespace,
+ // and the paths are PSR-0 directories.
+ $this->addNamespacePSR0(substr($prefix, 0, -1), $rootDirs);
+ }
+ elseif (FALSE !== strrpos($prefix, '\\')) {
+ // We assume that $prefix is meant as a namespace,
+ // and the paths are PSR-0 directories.
+ $namespace = $prefix;
+ $this->addNamespacePSR0($namespace, $rootDirs);
+ foreach ((array) $rootDirs as $rootDir) {
+ $this->addClassFile($prefix, $rootDir . '.php');
+ }
+ // @todo
+ // Register special plugins to cover other FQCNs
+ // that happen to begin with with the prefix.
+ }
+ elseif ('_' === substr($prefix, -1)) {
+ // We assume that $prefix is meant as a PEAR prefix,
+ // and the paths are PSR-0 directories.
+ $this->addPrefixPEAR(substr($prefix, 0, -1), $rootDirs, TRUE);
+ // @todo
+ // Register special plugins to cover other FQCNs
+ // that happen to begin with with the prefix.
+ }
+ else {
+ // We assume that $prefix is meant as a PEAR prefix OR as namespace,
+ // and the paths are PSR-0 or PEAR directories.
+ $this->addNamespacePSR0($prefix, $rootDirs);
+ $this->addPrefixPEAR($prefix, $rootDirs, TRUE);
+ foreach ((array) $rootDirs as $rootDir) {
+ $this->addClassFile($prefix, $rootDir . '.php');
+ }
+ // @todo
+ // Register special plugins to cover other FQCNs
+ // that happen to begin with with the prefix.
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixes(array $prefixes) {
+ $this->addPrefixesPSR0($prefixes);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefix($prefix, $rootDirs) {
+ $this->addPrefixPSR0($prefix, $rootDirs);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacesPSR0(array $namespaces) {
+ foreach ($namespaces as $namespace => $rootDirs) {
+ $this->addNamespacePSR0($namespace, $rootDirs);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacePSR0($namespace, $rootDirs) {
+ if (empty($namespace)) {
+ foreach ((array) $rootDirs as $rootDir) {
+ $rootDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addNamespacePlugin('', $rootDir, $this->plugins['ShallowPSR0']);
+ $this->finder->addPrefixPlugin('', $rootDir, $this->plugins['ShallowPEAR']);
+ }
+ }
+ else {
+ $logicalBasePath = $this->namespaceLogicalPath($namespace);
+ foreach ((array) $rootDirs as $rootDir) {
+ $baseDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : '';
+ $baseDir .= $logicalBasePath;
+ $this->finder->addNamespacePlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPSR0']);
+ }
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacesShallowPSR0(array $namespaces) {
+ foreach ($namespaces as $namespace => $baseDirs) {
+ $this->addNamespaceShallowPSR0($namespace, $baseDirs);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespaceShallowPSR0($namespace, $baseDirs) {
+ $logicalBasePath = $this->namespaceLogicalPath($namespace);
+ foreach ((array) $baseDirs as $baseDir) {
+ $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addNamespacePlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPSR0']);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixesPEAR(array $prefixes, $preventCollision = FALSE) {
+ foreach ($prefixes as $prefix => $rootDirs) {
+ $this->addPrefixPEAR($prefix, $rootDirs, $preventCollision);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixPEAR($prefix, $rootDirs, $preventCollision = FALSE) {
+ $logicalBasePath = $this->prefixLogicalPath($prefix);
+ $plugin = $preventCollision ? $this->plugins['ShallowPEAR_Uncertain'] : $this->plugins['ShallowPEAR'];
+ foreach ((array) $rootDirs as $rootDir) {
+ $baseDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : '';
+ $baseDir .= $logicalBasePath;
+ $this->finder->addPrefixPlugin($logicalBasePath, $baseDir, $plugin);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixesShallowPEAR(array $prefixes, $preventCollision = FALSE) {
+ foreach ($prefixes as $prefix => $baseDirs) {
+ $this->addPrefixPEAR($prefix, $baseDirs, $preventCollision);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixShallowPEAR($prefix, $baseDirs, $preventCollision = FALSE) {
+ $logicalBasePath = $this->prefixLogicalPath($prefix);
+ $plugin = $preventCollision ? $this->plugins['ShallowPEAR_Uncertain'] : $this->plugins['ShallowPEAR'];
+ foreach ((array) $baseDirs as $baseDir) {
+ $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addPrefixPlugin($logicalBasePath, $baseDir, $plugin);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacesPSRX(array $namespaces) {
+ foreach ($namespaces as $namespace => $baseDirs) {
+ $this->addNamespacePSRX($namespace, $baseDirs);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacePSRX($namespace, $baseDirs) {
+ $logicalBasePath = $this->namespaceLogicalPath($namespace);
+ foreach ((array) $baseDirs as $baseDir) {
+ $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addNamespacePlugin($logicalBasePath, $baseDir, $this->plugins['PSRX']);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespacePlugin($namespace, $baseDir, $plugin) {
+ $logicalBasePath = $this->namespaceLogicalPath($namespace);
+ $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addNamespacePlugin($logicalBasePath, $baseDir, $plugin);
+
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addPrefixPlugin($prefix, $baseDir, $plugin) {
+ $logicalBasePath = $this->prefixLogicalPath($prefix);
+ $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : '';
+ $this->finder->addPrefixPlugin($logicalBasePath, $baseDir, $plugin);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addClassMap(array $classMap, $override = FALSE) {
+ $this->finder->addClassMap($classMap, $override);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addClassFile($class, $file, $override = TRUE) {
+ $this->finder->addClassFile($class, $file, $override);
+ }
+
+ /**
+ * Replace the namespace separator with directory separator.
+ *
+ * @param string $namespace
+ * Namespace without trailing namespace separator.
+ *
+ * @return string
+ * Path fragment representing the namespace, with trailing DIRECTORY_SEPARATOR.
+ */
+ protected function namespaceLogicalPath($namespace) {
+ return
+ strlen($namespace)
+ ? str_replace('\\', DIRECTORY_SEPARATOR, $namespace . '\\')
+ : ''
+ ;
+ }
+
+ /**
+ * Convert the underscores of a prefix into directory separators.
+ *
+ * @param string $prefix
+ * Prefix, without trailing underscore.
+ *
+ * @return string
+ * Path fragment representing the prefix, with trailing DIRECTORY_SEPARATOR.
+ */
+ protected function prefixLogicalPath($prefix) {
+ return
+ strlen($prefix)
+ ? str_replace('_', DIRECTORY_SEPARATOR, $prefix . '_')
+ : ''
+ ;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/NamespaceInspector/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/NamespaceInspector/Interface.php
new file mode 100644
index 0000000..dfa2d41
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/Adapter/NamespaceInspector/Interface.php
@@ -0,0 +1,22 @@
+finder;
+ }
+
+ /**
+ * @param array $namespaces
+ * @return SearchableNamespaces_Interface
+ * @throws \Exception
+ */
+ function buildSearchableNamespaces(array $namespaces = array()) {
+ $searchable = new SearchableNamespaces_Default($this->finder);
+ $searchable->addNamespaces($namespaces);
+ return $searchable;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Abstract.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Abstract.php
new file mode 100644
index 0000000..8c85177
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Abstract.php
@@ -0,0 +1,59 @@
+= 0) {
+ spl_autoload_register(array($this, 'loadClass'), TRUE, $prepend);
+ }
+ elseif ($prepend) {
+ $loaders = spl_autoload_functions();
+ spl_autoload_register(array($this, 'loadClass'));
+ foreach ($loaders as $loader) {
+ spl_autoload_unregister($loader);
+ spl_autoload_register($loader);
+ }
+ }
+ else {
+ spl_autoload_register(array($this, 'loadClass'));
+ }
+ }
+
+ /**
+ * Unregister from the spl autoload stack.
+ */
+ function unregister() {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ function findFile($class) {
+ $api = new InjectedAPI_ClassFinder_FirstExistingFile($class);
+ $this->apiFindFile($api, $class);
+ return $api->getFile();
+ }
+
+ /**
+ * Load a class, and return the file that was successful.
+ *
+ * @param string $class
+ * The class to load.
+ *
+ * @return string
+ * The file that defined the class.
+ */
+ function loadClassGetFile($class) {
+ $api = new InjectedAPI_ClassFinder_LoadClassGetFile($class);
+ $this->apiFindFile($api, $class);
+ return $api->getFile();
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/Abstract.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/Abstract.php
new file mode 100644
index 0000000..8560d8c
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/Abstract.php
@@ -0,0 +1,33 @@
+decorated = $decorated;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function loadClass($class) {
+ $this->decorated->loadClass($class);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function apiFindFile(InjectedAPI_ClassFinder_Interface $api, $class) {
+ return $this->decorated->apiFindFile($api, $class);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/AbstractPrefixBased.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/AbstractPrefixBased.php
new file mode 100644
index 0000000..c4a5cde
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/AbstractPrefixBased.php
@@ -0,0 +1,36 @@
+checkRequirements();
+
+ $this->prefix = $prefix;
+ parent::__construct($decorated);
+ }
+
+ abstract protected function checkRequirements();
+
+ /**
+ * Set the cache prefix after a flush cache.
+ *
+ * @param string $prefix
+ * A prefix for the storage key in APC.
+ */
+ function setCachePrefix($prefix) {
+ $this->prefix = $prefix;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/ApcCache.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/ApcCache.php
new file mode 100644
index 0000000..fefa9fa
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/ApcCache.php
@@ -0,0 +1,33 @@
+prefix . $class)) ||
+ (!empty($file) && !is_file($file))
+ ) {
+ // Resolve cache miss.
+ apc_store($this->prefix . $class, $file = $this->decorated->loadClassGetFile($class));
+ }
+ else {
+ require $file;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/WinCache.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/WinCache.php
new file mode 100644
index 0000000..1ac87ef
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/WinCache.php
@@ -0,0 +1,30 @@
+prefix . $class)) {
+ // Resolve cache miss.
+ wincache_ucache_set($this->prefix . $class, $file = $this->decorated->loadClassGetFile($class), 0);
+ }
+ else {
+ require $file;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/XCache.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/XCache.php
new file mode 100644
index 0000000..dade937
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Cached/XCache.php
@@ -0,0 +1,31 @@
+prefix . $class)) {
+ if (FALSE !== $file = xcache_get($this->prefix . $class)) {
+ require $file;
+ }
+ }
+ else {
+ xcache_set($this->prefix . $class, $this->decorated->loadClassGetFile($class));
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Interface.php
new file mode 100644
index 0000000..2ab0990
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Interface.php
@@ -0,0 +1,70 @@
+suggestFile($file) with all suggestions we
+ * can find, until it returns TRUE. Once suggestFile() returns TRUE, we stop
+ * and return TRUE as well. The $file will be in the $api object, so we
+ * don't need to return it.
+ * @param string $class
+ * The name of the class, with all namespaces prepended.
+ * E.g. Some\Namespace\Some\Class
+ *
+ * @return boolean|NULL
+ * TRUE, if we found the file for the class.
+ * That is, if the $api->suggestFile($file) method returned TRUE one time.
+ * NULL, if we have no more suggestions.
+ */
+ public function apiFindFile(InjectedAPI_ClassFinder_Interface $api, $class);
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable.php
new file mode 100644
index 0000000..c7240f0
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable.php
@@ -0,0 +1,278 @@
+classMap)) {
+ $this->classMap = $classMap;
+ }
+ elseif ($override) {
+ $this->classMap = array_merge($classMap, $this->classMap);
+ }
+ else {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addClassFile($class, $file, $override = TRUE) {
+ if ($override || !isset($this->classMap[$class])) {
+ $this->classMap[$class] = $file;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addNamespacePlugin($logicalBasePath, $baseDir, NamespacePathPlugin_Interface $plugin) {
+ $this->namespaceMap[$logicalBasePath][$baseDir] = $plugin;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function addPrefixPlugin($logicalBasePath, $baseDir, PrefixPathPlugin_Interface $plugin) {
+ $this->prefixMap[$logicalBasePath][$baseDir] = $plugin;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function loadClass($class) {
+
+ // Discard initial namespace separator.
+ if ('\\' === $class[0]) {
+ $class = substr($class, 1);
+ }
+
+ // First check if the literal class name is registered.
+ if (isset($this->classMap[$class])) {
+ require $this->classMap[$class];
+ return TRUE;
+ }
+
+ // Distinguish namespace vs underscore-only.
+ // This is an internal implementation choice, and has nothing to do with
+ // whether or not the PSR-0 spec is correctly implemented.
+ if (FALSE !== $pos = strrpos($class, '\\')) {
+
+ // Loop through positions of '\\', backwards.
+ $logicalBasePath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos + 1));
+ $relativePath = substr($class, $pos + 1) . '.php';
+ if ($this->mapLoadClass($this->namespaceMap, $class, $logicalBasePath, $relativePath)) {
+ return TRUE;
+ }
+ }
+ else {
+
+ // The class is not within a namespace.
+ // Fall back to the prefix-based finder.
+ $logicalBasePath = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+ if ($this->mapLoadClass($this->prefixMap, $class, $logicalBasePath, '')) {
+ return TRUE;
+ }
+ }
+ }
+
+ /**
+ * Find the file for a class that in PSR-0 or PEAR would be in
+ * $psr_0_root . '/' . $logicalBasePath . $relativePath
+ *
+ * @param array $map
+ * Either the namespace map or the prefix
+ * @param string $class
+ * @param string $logicalBasePath
+ * First part of the canonical path, with trailing DIRECTORY_SEPARATOR.
+ * @param string $relativePath
+ * Second part of the canonical path, ending with '.php'.
+ *
+ * @return bool|NULL
+ * TRUE, if we found the file for the class.
+ * That is, if the $api->suggestFile($file) method returned TRUE one time.
+ * NULL, if we have no more suggestions.
+ */
+ protected function mapLoadClass(array $map, $class, $logicalBasePath, $relativePath) {
+
+ $path = $logicalBasePath . $relativePath;
+ while (TRUE) {
+ // Check any plugin registered for this fragment.
+ if (!empty($map[$logicalBasePath])) {
+ /**
+ * @var NamespacePathPlugin_Interface|PrefixPathPlugin_Interface $plugin
+ */
+ foreach ($map[$logicalBasePath] as $baseDir => $plugin) {
+ if ($plugin->pluginLoadClass($class, $baseDir, $relativePath)) {
+ return TRUE;
+ }
+ }
+ }
+
+ // Continue with parent fragment.
+ if ('' === $logicalBasePath) {
+ break;
+ }
+ elseif (DIRECTORY_SEPARATOR === $logicalBasePath) {
+ // This happens if a class begins with an underscore.
+ $logicalBasePath = '';
+ $relativePath = $path;
+ }
+ elseif (FALSE !== $pos = strrpos($logicalBasePath, DIRECTORY_SEPARATOR, -2)) {
+ $logicalBasePath = substr($logicalBasePath, 0, $pos + 1);
+ $relativePath = substr($path, $pos + 1);
+ }
+ else {
+ $logicalBasePath = '';
+ $relativePath = $path;
+ }
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param InjectedAPI_ClassFinder_Interface $api
+ * API object with a suggestFile() method.
+ * We are supposed to call $api->suggestFile($file) with all suggestions we
+ * can find, until it returns TRUE. Once suggestFile() returns TRUE, we stop
+ * and return TRUE as well. The $file will be in the $api object, so we
+ * don't need to return it.
+ * @param string $class
+ * The name of the class, with all namespaces prepended.
+ * E.g. Some\Namespace\Some\Class
+ *
+ * @return bool|NULL
+ * TRUE, if we found the file for the class.
+ * That is, if the $api->suggestFile($file) method returned TRUE one time.
+ * NULL, if we have no more suggestions.
+ */
+ public function apiFindFile(InjectedAPI_ClassFinder_Interface $api, $class) {
+
+ // Discard initial namespace separator.
+ if ('\\' === $class[0]) {
+ $class = substr($class, 1);
+ }
+
+ // First check if the literal class name is registered.
+ if (isset($this->classMap[$class])) {
+ if ($api->claimFile($this->classMap[$class])) {
+ return TRUE;
+ }
+ }
+
+ // Distinguish namespace vs underscore-only.
+ if (FALSE !== $pos = strrpos($class, '\\')) {
+
+ // Loop through positions of '\\', backwards.
+ $logicalBasePath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos + 1));
+ $relativePath = substr($class, $pos + 1) . '.php';
+ if ($this->apiMapFindFile($api, $this->namespaceMap, $logicalBasePath, $relativePath)) {
+ return TRUE;
+ }
+ }
+ else {
+
+ // The class is not within a namespace.
+ // Fall back to the prefix-based finder.
+ $logicalBasePath = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+ if ($this->apiMapFindFile($api, $this->prefixMap, $logicalBasePath, '')) {
+ return TRUE;
+ }
+ }
+ }
+
+ /**
+ * Find the file for a class that in PSR-0 or PEAR would be in
+ * $psr_0_root . '/' . $logicalBasePath . $relativePath
+ *
+ * @param array $map
+ * Either the namespace map or the prefix
+ * @param InjectedAPI_ClassFinder_Interface $api
+ * API object with a suggestFile() method.
+ * We are supposed to call $api->suggestFile($file) with all suggestions we
+ * can find, until it returns TRUE. Once suggestFile() returns TRUE, we stop
+ * and return TRUE as well. The $file will be in the $api object, so we
+ * don't need to return it.
+ * @param string $logicalBasePath
+ * First part of the canonical path, with trailing DIRECTORY_SEPARATOR.
+ * @param string $relativePath
+ * Second part of the canonical path, ending with '.php'.
+ *
+ * @return bool|NULL
+ * TRUE, if we found the file for the class.
+ * That is, if the $api->suggestFile($file) method returned TRUE one time.
+ * NULL, if we have no more suggestions.
+ */
+ protected function apiMapFindFile($api, $map, $logicalBasePath, $relativePath) {
+ $logicalPath = $logicalBasePath . $relativePath;
+ while (TRUE) {
+
+ // Check any plugin registered for this fragment.
+ if (!empty($map[$logicalBasePath])) {
+ /**
+ * @var NamespacePathPlugin_Interface|PrefixPathPlugin_Interface $plugin
+ */
+ foreach ($map[$logicalBasePath] as $baseDir => $plugin) {
+ if ($plugin->pluginFindFile($api, $baseDir, $relativePath)) {
+ return TRUE;
+ }
+ }
+ }
+
+ // Continue with parent fragment.
+ if ('' === $logicalBasePath) {
+ break;
+ }
+ elseif (DIRECTORY_SEPARATOR === $logicalBasePath) {
+ // This happens if a class begins with an underscore.
+ $logicalBasePath = '';
+ $relativePath = $logicalPath;
+ }
+ elseif (FALSE !== $pos = strrpos($logicalBasePath, DIRECTORY_SEPARATOR, -2)) {
+ $logicalBasePath = substr($logicalBasePath, 0, $pos + 1);
+ $relativePath = substr($logicalPath, $pos + 1);
+ }
+ else {
+ $logicalBasePath = '';
+ $relativePath = $logicalPath;
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php
new file mode 100644
index 0000000..bb17698
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php
@@ -0,0 +1,73 @@
+namespace = $namespace;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getNamespace() {
+ return $this->namespace;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getClassName($relativeClassName) {
+ return $this->namespace . $relativeClassName;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php
new file mode 100644
index 0000000..c754518
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php
@@ -0,0 +1,32 @@
+classes);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function fileWithClass($file, $relativeClassName) {
+ $this->classes[$this->getClassName($relativeClassName)] = TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function fileWithClassCandidates($file, array $relativeClassNames) {
+ foreach ($relativeClassNames as $relativeClassName) {
+ $this->classes[$this->getClassName($relativeClassName)] = TRUE;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php
new file mode 100644
index 0000000..c1437a1
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php
@@ -0,0 +1,25 @@
+classes;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function confirmedFileWithClass($file, $class) {
+ $this->classes[$class] = $class;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php
new file mode 100644
index 0000000..e06a1c9
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php
@@ -0,0 +1,67 @@
+includedFileWithClassCandidate($file, $relativeClassName);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function fileWithClassCandidates($file, array $relativeClassNames) {
+ include_once $file;
+ foreach ($relativeClassNames as $relativeClassName) {
+ $this->includedFileWithClassCandidate($file, $relativeClassName);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function includedFileWithClassCandidate($file, $relativeClassName) {
+ if (class_exists($class = $this->getNamespace() . $relativeClassName, FALSE)) {
+ $this->confirmedFileWithClass($file, $class);
+ }
+ elseif (interface_exists($class, FALSE)) {
+ $this->confirmedFileWithInterface($file, $class);
+ }
+ elseif (PHP_VERSION_ID >= 50400 && trait_exists($class, FALSE)) {
+ $this->confirmedFileWithTrait($file, $class);
+ }
+ }
+
+ /**
+ * @param string $file
+ * @param string $class
+ */
+ abstract protected function confirmedFileWithClass($file, $class);
+
+ /**
+ * @param string $file
+ * @param string $interface
+ */
+ protected function confirmedFileWithInterface($file, $interface) {
+ // Do nothing by default.
+ }
+
+ /**
+ * @param string $file
+ * @param string $trait
+ */
+ protected function confirmedFileWithTrait($file, $trait) {
+ // Do nothing by default.
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php
new file mode 100644
index 0000000..6b3ad13
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php
@@ -0,0 +1,64 @@
+setNamespace().
+ * E.g. 'Foo\\Bar', so that the fully-qualified class name would be
+ * 'MyVendor\\MyPackage\\Foo\\Bar',
+ */
+ function fileWithClass($file, $relativeClassName);
+
+ /**
+ * A file was discovered that may define any of the given classes.
+ *
+ * @param string $file
+ * The file that was found and may contain any or none of the classes.
+ * @param array $relativeClassNames
+ * Array of relative class names for classes that *could* be in this file.
+ * With PSR-0, these can be different variations of the underscore.
+ * The one with the least underscores will always be at index 0.
+ * Class names are relative to the namespace previously specified with
+ * ->setNamespace().
+ */
+ function fileWithClassCandidates($file, array $relativeClassNames);
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Mock.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Mock.php
new file mode 100644
index 0000000..7899ea6
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Mock.php
@@ -0,0 +1,38 @@
+called;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function setNamespace($namespace) {
+ $this->called[] = array(__FUNCTION__, func_get_args());
+ parent::setNamespace($namespace);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function fileWithClass($file, $relativeClassName) {
+ $this->called[] = array(__FUNCTION__, func_get_args());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function fileWithClassCandidates($file, array $relativeClassNames) {
+ $this->called[] = array(__FUNCTION__, func_get_args());
+ }
+}
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Abstract.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Abstract.php
new file mode 100644
index 0000000..73b88a0
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Abstract.php
@@ -0,0 +1,66 @@
+className = $class_name;
+ }
+
+ /**
+ * Get the name of the class we are looking for.
+ *
+ * @return string
+ * The class we are looking for.
+ */
+ function getClass() {
+ return $this->className;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFile($file) {
+ if (is_file($file)) {
+ return $this->claimFile($file);
+ }
+ return FALSE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFileCandidate($file) {
+ if (is_file($file)) {
+ return $this->claimFileCandidate($file);
+ }
+ return FALSE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFile_checkIncludePath($file) {
+ if (FALSE !== $file = Util::findFileInIncludePath($file)) {
+ return $this->claimFile($file);
+ }
+ return FALSE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFileCandidate_checkIncludePath($file) {
+ if (FALSE !== $file = Util::findFileInIncludePath($file)) {
+ return $this->claimFileCandidate($file);
+ }
+ return FALSE;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php
new file mode 100644
index 0000000..e19d6c9
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php
@@ -0,0 +1,35 @@
+files;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFile($file) {
+ $this->files[$file] = TRUE;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFileCandidate($file) {
+ $this->files[$file] = FALSE;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php
new file mode 100644
index 0000000..5c43d64
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php
@@ -0,0 +1,48 @@
+destination;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFile($file) {
+ $this->destination = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFileCandidate($file) {
+ $this->destination = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFile($file) {
+ $this->destination = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFileCandidate($file) {
+ $this->destination = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFile_checkIncludePath($file) {
+ // Include path is not supported when looking for a destination.
+ return FALSE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFileCandidate_checkIncludePath($file) {
+ // Include path is not supported when looking for a destination.
+ return FALSE;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FirstExistingFile.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FirstExistingFile.php
new file mode 100644
index 0000000..a2cab70
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FirstExistingFile.php
@@ -0,0 +1,38 @@
+file;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFile($file) {
+ $this->file = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFileCandidate($file) {
+ $this->file = $file;
+ return TRUE;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php
new file mode 100644
index 0000000..5521f9a
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php
@@ -0,0 +1,111 @@
+className, FALSE);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/LoadClassGetFile.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/LoadClassGetFile.php
new file mode 100644
index 0000000..f92f439
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/ClassFinder/LoadClassGetFile.php
@@ -0,0 +1,63 @@
+file;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFile($file) {
+ if (is_file($file)) {
+ include $file;
+ $this->file = $file;
+ return TRUE;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function guessFileCandidate($file) {
+ if (is_file($file)) {
+ include_once $file;
+ if (Util::classIsDefined($this->className)) {
+ $this->file = $file;
+ return TRUE;
+ }
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFile($file) {
+ require $file;
+ $this->file = $file;
+ return TRUE;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function claimFileCandidate($file) {
+ require_once $file;
+ if (Util::classIsDefined($this->className)) {
+ $this->file = $file;
+ return TRUE;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/Interface.php
new file mode 100644
index 0000000..b17037f
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/Interface.php
@@ -0,0 +1,25 @@
+api = $api;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function setNamespace($namespace) {
+ $this->api->setNamespace($namespace);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanNamespace.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanNamespace.php
new file mode 100644
index 0000000..04c04d5
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanNamespace.php
@@ -0,0 +1,20 @@
+pluginScanNamespace($this->api, $baseDir, $relativePath);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function namespaceParentDirectoryPlugin($baseDir, $relativeNamespace, $plugin) {
+ throw new \Exception("This should only ever be called during recursive scans.");
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanRecursive.php b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanRecursive.php
new file mode 100644
index 0000000..a17429b
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/InjectedAPI/NamespaceInspector/ScanRecursive.php
@@ -0,0 +1,20 @@
+pluginScanRecursive($this->api, $baseDir, $relativePath);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function namespaceParentDirectoryPlugin($baseDir, $relativeNamespace, $plugin) {
+ $plugin->pluginScanParentRecursive($this->api, $baseDir, $relativeNamespace);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Interface.php
new file mode 100644
index 0000000..1736438
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Interface.php
@@ -0,0 +1,13 @@
+normalizeNamespaces($namespaces);
+ if ($recursive) {
+ $this->apiInspectNamespacesRecursive($api, $namespaces);
+ }
+ foreach ($namespaces as $namespace) {
+ $this->apiInspectNamespace($api, $namespace);
+ }
+ }
+
+ /**
+ * @param array $namespaces
+ * Array of namespaces with arbitrary keys, and
+ * with or without trailing or leading namespace separators.
+ * @return array
+ * Array of namespaces, where key and value are identical,
+ * The root namespace is represented by an empty string.
+ * Every other namespace is represented with a trailing namespace separator,
+ * but without a leading namespace separator.
+ */
+ protected function normalizeNamespaces(array $namespaces) {
+ $normalized = array();
+ foreach ($namespaces as $namespace) {
+ $namespace = trim($namespace, '\\') . '\\';
+ if ('\\' === $namespace) {
+ $namespace = '';
+ }
+ $normalized[$namespace] = $namespace;
+ }
+ return $normalized;
+ }
+
+ /**
+ * @param InjectedAPI_NamespaceInspector_Interface $api
+ * @param array $namespaces
+ */
+ protected function apiInspectNamespacesRecursive(InjectedAPI_NamespaceInspector_Interface $api, array $namespaces) {
+
+ foreach ($this->namespaceMap as $logicalBasePath => $plugins) {
+ $baseNamespace = str_replace(DIRECTORY_SEPARATOR, '\\', $logicalBasePath);
+ $baseNamespacePrefix = $baseNamespace;
+ while ('' !== $baseNamespacePrefix) {
+ // Move one fragment from the prefix to the relative base namepsace.
+ if (FALSE === $pos = strrpos($baseNamespacePrefix, '\\', -2)) {
+ // $baseNamespacePrefix is e.g. 'MyVendor\\'.
+ $pos = 0;
+ $baseNamespacePrefix = '';
+ }
+ else {
+ // $baseNamespacePrefix is e.g. 'MyVendor\\MyPackage\\Foo\\'.
+ ++$pos;
+ $baseNamespacePrefix = substr($baseNamespacePrefix, 0, $pos);
+ }
+ if (isset($namespaces[$baseNamespacePrefix])) {
+ $api->setNamespace($baseNamespacePrefix);
+ $relativeBaseNamespace = substr($baseNamespace, $pos);
+ /**
+ * @var NamespacePathPlugin_Interface $plugin
+ */
+ foreach ($plugins as $baseDir => $plugin) {
+ $api->namespaceParentDirectoryPlugin($baseDir, $relativeBaseNamespace, $plugin);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param InjectedAPI_NamespaceInspector_Interface $api
+ * @param string $namespace
+ * The namespace, e.g. 'MyVendor\\MyPackage\\'.
+ */
+ protected function apiInspectNamespace(InjectedAPI_NamespaceInspector_Interface $api, $namespace) {
+
+ $logicalPath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace);
+ $logicalBasePath = $logicalPath;
+ $relativePath = '';
+
+ $api->setNamespace($namespace);
+
+ while (TRUE) {
+ // Check any plugin registered for this fragment.
+ if (!empty($this->namespaceMap[$logicalBasePath])) {
+ /**
+ * @var NamespacePathPlugin_Interface $plugin
+ */
+ foreach ($this->namespaceMap[$logicalBasePath] as $baseDir => $plugin) {
+ $api->namespaceDirectoryPlugin($baseDir, $relativePath, $plugin);
+ }
+ }
+
+ // Continue with parent fragment.
+ if ('' === $logicalBasePath) {
+ break;
+ }
+ elseif (DIRECTORY_SEPARATOR === $logicalBasePath) {
+ // This happens if a class begins with an underscore.
+ $logicalBasePath = '';
+ $relativePath = $logicalPath;
+ }
+ elseif (FALSE !== $pos = strrpos($logicalBasePath, DIRECTORY_SEPARATOR, -2)) {
+ $logicalBasePath = substr($logicalBasePath, 0, $pos + 1);
+ $relativePath = substr($logicalPath, $pos + 1);
+ }
+ else {
+ $logicalBasePath = '';
+ $relativePath = $logicalPath;
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Pluggable/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Pluggable/Interface.php
new file mode 100644
index 0000000..7c9ed0c
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespaceInspector/Pluggable/Interface.php
@@ -0,0 +1,5 @@
+getClass() will return the FQCN of the class we are looking for.
+ * @param string $baseDir
+ * Physical base path associated with the logical base path.
+ * @param string $relativePath
+ * Second part of the logical path built from the FQCN.
+ *
+ * @return boolean
+ * TRUE, if the $api did return TRUE for one candidate file.
+ */
+ function pluginFindFile($api, $baseDir, $relativePath);
+
+ /**
+ * Shortcut to directly load the class, with no $api in the way.
+ *
+ * @param string $class
+ * The class that is to be loaded.
+ * @param string $baseDir
+ * Physical base path associated with the logical base path.
+ * @param string $relativePath
+ * Second part of the logical path built from the FQCN.
+ *
+ * @return boolean
+ * TRUE, if the class was loaded.
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath);
+
+ /**
+ * @param InjectedAPI_ClassFileVisitor_Interface $api
+ * @param string $baseDir
+ * @param string $relativePath
+ */
+ function pluginScanNamespace($api, $baseDir, $relativePath);
+
+ /**
+ * @param InjectedAPI_ClassFileVisitor_Interface $api
+ * @param string $baseDir
+ * @param string $relativePath
+ */
+ function pluginScanRecursive($api, $baseDir, $relativePath);
+
+ /**
+ * @param InjectedAPI_ClassFileVisitor_Interface $api
+ * @param string $baseDir
+ * @param string $relativeBaseNamespace
+ */
+ function pluginScanParentRecursive($api, $baseDir, $relativeBaseNamespace);
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php
new file mode 100644
index 0000000..c66b0dd
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php
@@ -0,0 +1,80 @@
+guessFile($baseDir . $relativePath);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if (is_file($file = $baseDir . $relativePath)) {
+ include $file;
+ return TRUE;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanNamespace($api, $baseDir, $relativePath) {
+ if (is_dir($dir = $baseDir . $relativePath)) {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $api->fileWithClass($fileinfo->getPathname(), $fileinfo->getBasename('.php'));
+ }
+ }
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanRecursive($api, $baseDir, $relativePath) {
+ if (is_dir($dir = $baseDir . $relativePath)) {
+ $this->doScanRecursive($api, $dir);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanParentRecursive($api, $baseDir, $relativeBaseNamespace) {
+ if (is_dir($baseDir)) {
+ $this->doScanRecursive($api, $baseDir, $relativeBaseNamespace);
+ }
+ }
+
+ /**
+ * @param InjectedAPI_ClassFileVisitor_Interface $api
+ * @param string $dir
+ * @param string $relativeNamespace
+ */
+ protected function doScanRecursive($api, $dir, $relativeNamespace = '') {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $relativeClassName = $relativeNamespace . $fileinfo->getBasename('.php');
+ $api->fileWithClass($fileinfo->getPathname(), $relativeClassName);
+ }
+ elseif (!$fileinfo->isDot() && $fileinfo->isDir()) {
+ $relativeSubNamespace = $relativeNamespace . $fileinfo->getFilename() . '\\';
+ $this->doScanRecursive($api, $fileinfo->getPathname(), $relativeSubNamespace);
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php
new file mode 100644
index 0000000..b02eb46
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php
@@ -0,0 +1,118 @@
+guessFileCandidate($baseDir . $relativePath)) {
+ return TRUE;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+
+ // Replace the underscores after the last directory separator.
+ if (FALSE !== $pos = strrpos($relativePath, DIRECTORY_SEPARATOR)) {
+ $relativePath = substr($relativePath, 0, $pos) . str_replace('_', DIRECTORY_SEPARATOR, substr($relativePath, $pos));
+ }
+ else {
+ $relativePath = str_replace('_', DIRECTORY_SEPARATOR, $relativePath);
+ }
+
+ // Check whether the file exists.
+ if (is_file($file = $baseDir . $relativePath)) {
+ // We don't know if the file defines the class,
+ // and whether it was already included.
+ include_once $file;
+ // This check happens inline for micro-optimization.
+ return class_exists($class, FALSE)
+ || interface_exists($class, FALSE)
+ || (PHP_VERSION_ID >= 50400 && trait_exists($class, FALSE))
+ ;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanNamespace($api, $baseDir, $relativePath) {
+ if (is_dir($dir = $baseDir . $relativePath)) {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $api->fileWithClassCandidates($fileinfo->getPathname(), array($fileinfo->getBasename('.php')));
+ }
+ }
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanRecursive($api, $baseDir, $relativePath) {
+ if (is_dir($dir = $baseDir . $relativePath)) {
+ $this->doScanRecursive($api, $dir);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanParentRecursive($api, $baseDir, $relativeBaseNamespace) {
+ if (is_dir($baseDir)) {
+ $this->doScanRecursive($api, $baseDir, array($relativeBaseNamespace));
+ }
+ }
+
+ /**
+ * @param InjectedAPI_ClassFileVisitor_Interface $api
+ * @param string $dir
+ * @param array $relativeNamespaces
+ */
+ protected function doScanRecursive($api, $dir, $relativeNamespaces = array('')) {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $relativeClassNames = array();
+ foreach ($relativeNamespaces as $relativeNamespace) {
+ $relativeClassNames[] = $relativeNamespace . $fileinfo->getBasename('.php');
+ }
+ if (!empty($relativeClassNames)) {
+ $api->fileWithClassCandidates($fileinfo->getPathname(), $relativeClassNames);
+ }
+ }
+ elseif (!$fileinfo->isDot() && $fileinfo->isDir()) {
+ $relativeSubNamespaces = array($relativeNamespaces[0] . $fileinfo->getFilename() . '\\');
+ foreach ($relativeNamespaces as $relativeNamespace) {
+ $relativeSubNamespaces[] = $relativeNamespace . $fileinfo->getFilename() . '_';
+ }
+ $this->doScanRecursive($api, $fileinfo->getPathname(), $relativeSubNamespaces);
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php
new file mode 100644
index 0000000..508568c
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php
@@ -0,0 +1,104 @@
+guessFile($baseDir . $relativePath)) {
+ return TRUE;
+ }
+ }
+
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+
+ // Check for underscores after the last directory separator.
+ // In other words: Check for the last underscore, and whether that is
+ // followed by a directory separator.
+ if (FALSE !== strrpos($relativePath, DIRECTORY_SEPARATOR)) {
+ // Ignore this class.
+ return;
+ }
+ // We are safe, the class is not in a sub-namespace.
+ // So we can proceed with class loading.
+
+ // Replace all underscores in the suffix part.
+ $relativePath = str_replace('_', DIRECTORY_SEPARATOR, $relativePath);
+
+ // We "guess", because we don't know whether the file exists.
+ if (is_file($file = $baseDir . $relativePath)) {
+ include $file;
+ return TRUE;
+ }
+ }
+
+ function pluginScanNamespace($api, $baseDir, $relativePath) {
+ // Check that $namespace is NOT a sub-namespace of the registered namespace.
+ if ('' === $relativePath) {
+ if (is_dir($baseDir)) {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($baseDir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $api->fileWithClass($fileinfo->getPathname(), '\\' . $fileinfo->getBasename('.php'));
+ }
+ }
+ }
+ }
+ }
+
+ function pluginScanRecursive($api, $baseDir, $relativePath) {
+ // Check that $namespace is NOT a sub-namespace of the registered namespace.
+ if ('' === $relativePath) {
+ if (is_dir($baseDir)) {
+ $this->doScanRecursive($api, $baseDir);
+ }
+ }
+ }
+
+ protected function doScanRecursive($api, $dir, $relativeNamespace = '\\') {
+ /**
+ * @var \DirectoryIterator $fileinfo
+ */
+ foreach (new \DirectoryIterator($dir) as $fileinfo) {
+ // @todo With PHP 5.3.6, this could be $fileinfo->getExtension().
+ if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+ $api->fileWithClass($fileinfo->getPathname(), $relativeNamespace . $fileinfo->getBasename('.php'));
+ }
+ elseif (!$fileinfo->isDot() && $fileinfo->isDir()) {
+ $relativeSubNamespace = $relativeNamespace . $fileinfo->getFilename() . '_';
+ $this->doScanRecursive($api, $fileinfo->getPathname(), $relativeSubNamespace);
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php
new file mode 100644
index 0000000..dd2fcb6
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php
@@ -0,0 +1,37 @@
+relativePrefixes[$relativePrefix] = strlen($relativePrefix);
+ }
+
+ function pluginFindFile($api, $baseDir, $relativePath) {
+ if ($this->checkPrefix($relativePath)) {
+ return parent::pluginFindFile($api, $baseDir, $relativePath);
+ }
+ }
+
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if ($this->checkPrefix($relativePath)) {
+ return parent::pluginLoadClass($class, $baseDir, $relativePath);
+ }
+ }
+
+ protected function checkPrefix($relativePath) {
+ foreach ($this->relativePrefixes as $relativePrefix => $length) {
+ if (!strncmp($relativePath, $relativePrefix, $length)) {
+ return TRUE;
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoConflict.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoConflict.php
new file mode 100644
index 0000000..a926dbf
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoConflict.php
@@ -0,0 +1,48 @@
+guessFile($baseDir . $relativePath)) {
+ return TRUE;
+ }
+ }
+
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ // We need to replace the underscores after the last directory separator.
+ if (FALSE !== $pos = strrpos($relativePath, DIRECTORY_SEPARATOR)) {
+ $relativePath = substr($relativePath, 0, $pos) . str_replace('_', DIRECTORY_SEPARATOR, substr($relativePath, $pos));
+ }
+ else {
+ $relativePath = str_replace('_', DIRECTORY_SEPARATOR, $relativePath);
+ }
+ // We don't know if the file exists.
+ if (is_file($file = $baseDir . $relativePath)) {
+ // We assume that the file defines the class.
+ include $file;
+ return TRUE;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php
new file mode 100644
index 0000000..22c0b50
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php
@@ -0,0 +1,28 @@
+guessFile_checkIncludePath($baseDir . $relativePath)) {
+ return TRUE;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ // We need to replace the underscores after the last directory separator.
+ if (FALSE !== $pos = strrpos($relativePath, DIRECTORY_SEPARATOR)) {
+ $relativePath = substr($relativePath, 0, $pos) . str_replace('_', DIRECTORY_SEPARATOR, substr($relativePath, $pos));
+ }
+ else {
+ $relativePath = str_replace('_', DIRECTORY_SEPARATOR, $relativePath);
+ }
+ // We don't know if the file exists.
+ if (FALSE !== $file = Util::findFileInIncludePath($baseDir . $relativePath)) {
+ include_once $file;
+ return Util::classIsDefined($class);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanNamespace($api, $baseDir, $relativePath) {
+ throw new \Exception("Class discovery is not supported with 'use include path' setting.");
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginScanRecursive($api, $baseDir, $relativePath) {
+ throw new \Exception("Class discovery is not supported with 'use include path' setting.");
+ }
+}
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Exotic/CamelSwap.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Exotic/CamelSwap.php
new file mode 100644
index 0000000..35f7321
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Exotic/CamelSwap.php
@@ -0,0 +1,42 @@
+guessFile($baseDir . $this->transformRelativePath($relativePath));
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if (is_file($file = $baseDir . $this->transformRelativePath($relativePath))) {
+ include_once $file;
+ return TRUE;
+ }
+ }
+
+ protected function transformRelativePath($relativePath) {
+ $pieces = Util::camelCaseExplode(substr($relativePath, 0, -4));
+ $pieces = array_reverse($pieces);
+ return implode(DIRECTORY_SEPARATOR, $pieces) . '.php';
+ }
+}
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Interface.php
new file mode 100644
index 0000000..fd29b26
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/Interface.php
@@ -0,0 +1,41 @@
+getClass() will return the FQCN of the class we are looking for.
+ * @param string $baseDir
+ * Physical base path associated with the logical base path.
+ * @param string $relativePath
+ * Second part of the logical path built from the FQCN.
+ *
+ * @return boolean
+ * TRUE, if the $api did return TRUE for one candidate file.
+ */
+ function pluginFindFile($api, $baseDir, $relativePath);
+
+ /**
+ * Shortcut to directly load the class, with no $api in the way.
+ *
+ * @param string $class
+ * The class that is to be loaded.
+ * @param string $baseDir
+ * Physical base path associated with the logical base path.
+ * @param string $relativePath
+ * Second part of the logical path built from the FQCN.
+ *
+ * @return boolean
+ * TRUE, if the class was loaded.
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath);
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR.php
new file mode 100644
index 0000000..dd1417f
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR.php
@@ -0,0 +1,17 @@
+guessFile($baseDir . $relativePath);
+ }
+
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if (is_file($file = $baseDir . $relativePath)) {
+ include $file;
+ return TRUE;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php
new file mode 100644
index 0000000..3cff2f2
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php
@@ -0,0 +1,53 @@
+relativePrefixes[$relativePrefix] = strlen($relativePrefix);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginFindFile($api, $baseDir, $relativePath) {
+ if ($this->checkPrefix($relativePath)) {
+ return $api->guessFile($baseDir . $relativePath);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if ($this->checkPrefix($relativePath)) {
+ if (is_file($file = $baseDir . $relativePath)) {
+ include $file;
+ return TRUE;
+ }
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function checkPrefix($relativePath) {
+ foreach ($this->relativePrefixes as $relativePrefix => $length) {
+ if (!strncmp($relativePath, $relativePrefix, $length)) {
+ return TRUE;
+ }
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php
new file mode 100644
index 0000000..b1d38a7
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php
@@ -0,0 +1,27 @@
+guessFileCandidate($baseDir . $relativePath);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ if (is_file($file = $baseDir . $relativePath)) {
+ include_once $file;
+ // This check happens inline for micro-optimization.
+ return class_exists($class, FALSE)
+ || interface_exists($class, FALSE)
+ || (PHP_VERSION_ID >= 50400 && trait_exists($class, FALSE))
+ ;
+ }
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/UseIncludePath.php b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/UseIncludePath.php
new file mode 100644
index 0000000..0c8303d
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/UseIncludePath.php
@@ -0,0 +1,27 @@
+guessFile_checkIncludePath($baseDir . $relativePath)) {
+ return TRUE;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function pluginLoadClass($class, $baseDir, $relativePath) {
+ // We don't know if the file exists.
+ if (FALSE !== $file = Util::findFileInIncludePath($baseDir . $relativePath)) {
+ include_once $file;
+ return Util::classIsDefined($class);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/RegistrationHub.php b/core/vendor/donquixote/krautoload/src/Krautoload/RegistrationHub.php
new file mode 100644
index 0000000..520b16a
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/RegistrationHub.php
@@ -0,0 +1,36 @@
+finder instanceof NamespaceInspector_Interface) {
+ throw new \Exception("Introspection not possible with the given class loader object.");
+ }
+ return parent::buildSearchableNamespaces($namespaces);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Default.php b/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Default.php
new file mode 100644
index 0000000..f345f9b
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Default.php
@@ -0,0 +1,141 @@
+finder = $finder;
+ }
+
+ /**
+ * @param NamespaceInspector_Interface $finder
+ */
+ function setFinder(NamespaceInspector_Interface $finder) {
+ $this->finder = $finder;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespace($namespace) {
+ $this->namespaces[$namespace] = $namespace;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function setNamespaces(array $namespaces) {
+ $this->namespaces = array();
+ $this->addNamespaces($namespaces);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function addNamespaces(array $namespaces) {
+ foreach ($namespaces as $namespace) {
+ $this->namespaces[$namespace] = $namespace;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function getNamespaces() {
+ return $this->namespaces;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function buildSearchableNamespaces(array $namespaces = array()) {
+ $new = new self($this->finder);
+ $new->addNamespaces($namespaces);
+ return $new;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function buildFromSuffix($suffix) {
+ if ('\\' !== $suffix[0]) {
+ $suffix = '\\' . $suffix;
+ }
+ $new = $this->buildSearchableNamespaces();
+ foreach ($this->namespaces as $namespace) {
+ $new->addNamespace($namespace . $suffix);
+ }
+ return $new;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function apiVisitClassFiles(InjectedAPI_ClassFileVisitor_Interface $api, $recursive = FALSE) {
+ $namespaceVisitorAPI = $recursive
+ ? new InjectedAPI_NamespaceInspector_ScanRecursive($api)
+ : new InjectedAPI_NamespaceInspector_ScanNamespace($api)
+ ;
+ $this->apiInspectNamespaces($namespaceVisitorAPI, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function apiInspectNamespaces(InjectedAPI_NamespaceInspector_Interface $api, $recursive = FALSE) {
+ $this->finder->apiInspectNamespaces($api, $this->namespaces, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function discoverExistingClasses($recursive = FALSE) {
+ $api = new InjectedAPI_ClassFileVisitor_CollectExistingClasses();
+ $this->apiVisitClassFiles($api, $recursive);
+ return $api->getCollectedClasses();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function discoverCandidateClasses($recursive = FALSE) {
+ $api = new InjectedAPI_ClassFileVisitor_CollectCandidateClasses();
+ $this->apiVisitClassFiles($api, $recursive);
+ return $api->getCollectedClasses();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function classExistsInNamespaces($class) {
+ return $this->classIsInNamespaces($class) && $this->classExistsInFinder($class);
+ }
+
+ protected function classIsInNamespaces($class) {
+ $prefix = $class;
+ while (FALSE !== $pos = strrpos($prefix, '\\')) {
+ $prefix = substr($prefix, 0, $pos);
+ if (isset($this->namespaces[$prefix])) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ protected function classExistsInFinder($class) {
+ if (Util::classIsDefined($class)) {
+ $api = new InjectedAPI_ClassFinder_FindExistingClass($class);
+ }
+ else {
+ $api = new InjectedAPI_ClassFinder_LoadClass($class);
+ }
+ return $this->finder->apiFindFile($api, $class);
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Interface.php b/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Interface.php
new file mode 100644
index 0000000..0d74926
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/src/Krautoload/SearchableNamespaces/Interface.php
@@ -0,0 +1,97 @@
+ $item) {
+ if ($item['function'] === 'spl_autoload_call') {
+ switch ($f = $trace[$i + 1]['function']) {
+ case 'class_exists':
+ case 'interface_exists':
+ case 'method_exists':
+ case 'trait_exists':
+ case 'is_callable':
+ // @todo Add more cases.
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks whether an identifier is defined as either a class, interface or
+ * trait. Does not trigger autoloading.
+ *
+ * @param string $class
+ * @return bool
+ */
+ static function classIsDefined($class) {
+ return class_exists($class, FALSE)
+ || interface_exists($class, FALSE)
+ || (PHP_VERSION_ID >= 50400 && trait_exists($class, FALSE))
+ ;
+ }
+
+ /**
+ * Check if a file exists, considering the full include path.
+ *
+ * @param string $file
+ * The filepath
+ * @return boolean
+ * TRUE, if the file exists somewhere in include path.
+ * FALSE, otherwise.
+ */
+ static function fileExistsInIncludePath($file) {
+ if (function_exists('stream_resolve_include_path')) {
+ // Use the PHP 5.3.1+ way of doing this.
+ return (FALSE !== stream_resolve_include_path($file));
+ }
+ elseif ($file{0} === DIRECTORY_SEPARATOR) {
+ // That's an absolute path already.
+ return file_exists($file);
+ }
+ else {
+ // Manually loop all candidate paths.
+ foreach (explode(PATH_SEPARATOR, get_include_path()) as $base_dir) {
+ if (file_exists($base_dir . DIRECTORY_SEPARATOR . $file)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ /**
+ * Check if a file exists, considering the full include path.
+ *
+ * @param string $file
+ * The filepath
+ * @return boolean|string
+ * The resolved file path, if the file exists in the include path.
+ * FALSE, otherwise.
+ */
+ static function findFileInIncludePath($file) {
+ if (function_exists('stream_resolve_include_path')) {
+ // Use the PHP 5.3.1+ way of doing this.
+ return stream_resolve_include_path($file);
+ }
+ elseif ($file{0} === DIRECTORY_SEPARATOR) {
+ // That's an absolute path already.
+ return file_exists($file) ? $file : FALSE;
+ }
+ else {
+ // Manually loop all candidate paths.
+ foreach (explode(PATH_SEPARATOR, get_include_path()) as $base_dir) {
+ if (file_exists($base_dir . DIRECTORY_SEPARATOR . $file)) {
+ return $base_dir . DIRECTORY_SEPARATOR . $file;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ /**
+ * @param string $string
+ * The original string, that we want to explode.
+ * @param boolean $lowercase
+ * should the result be lowercased?
+ * @param string $example_string
+ * Example to specify how to deal with multiple uppercase characters.
+ * Can be something like "AA Bc" or "A A Bc" or "AABc".
+ * @param boolean $glue
+ * Allows to implode the fragments with sth like "_" or "." or " ".
+ * If $glue is FALSE, it will just return an array.
+ *
+ * @throws \Exception
+ * @return array|string
+ * An indexed array of pieces, if $glue is FALSE.
+ * A glued string, if $glue is a string.
+ */
+ static function camelCaseExplode($string, $lowercase = TRUE, $example_string = 'AA Bc', $glue = FALSE) {
+ static $regexp_available = array(
+ '/([A-Z][^A-Z]*)/',
+ '/([A-Z][^A-Z]+)/',
+ '/([A-Z]+[^A-Z]*)/',
+ );
+ static $regexp_by_example = array();
+ if (!isset($regexp_by_example[$example_string])) {
+ foreach ($regexp_available as $regexp) {
+ if (implode(' ', preg_split(
+ $regexp,
+ str_replace(' ', '', $example_string),
+ -1,
+ PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
+ )) == $example_string) {
+ break;
+ }
+ }
+ if (!isset($regexp)) {
+ throw new \Exception("Invalid example string '$example_string'.");
+ }
+ $regexp_by_example[$example_string] = $regexp;
+ }
+ $array = preg_split(
+ $regexp_by_example[$example_string],
+ $string,
+ -1,
+ PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
+ );
+ if ($lowercase) {
+ $array = array_map('strtolower', $array);
+ }
+ return (FALSE !== $glue) ? implode($glue, $array) : $array;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/tests/fixtures/alpha/NamespaceCollision/A/Bar.php b/core/vendor/donquixote/krautoload/tests/fixtures/alpha/NamespaceCollision/A/Bar.php
new file mode 100644
index 0000000..f0f97a5
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/tests/fixtures/alpha/NamespaceCollision/A/Bar.php
@@ -0,0 +1,8 @@
+ 'ApcCache',
+ 'cache_prefix' => $prefix = 'krautoload-test-07a9812c3469d38u567c64650',
+));
+
+$krautoload->addClassMap(array(
+ 'ClassMap\Foo\Bar' => 'tests/fixtures/src-classmap/classmap-foo-bar.php',
+));
+$krautoload->addNamespacePSR0('Namespaced2', 'tests/fixtures/src-psr0');
+$krautoload->addPrefixPEAR('Pearlike2', 'tests/fixtures/src-psr0');
+$krautoload->addNamespacePSRX('MyVendor\MyPackage', 'tests/fixtures/src-psrx');
+
+new ClassMap\Foo\Bar;
+new Namespaced2\Foo;
+new Pearlike2_Foo;
+new MyVendor\MyPackage\Foo\Bar;
+
+if (class_exists('ClassMap\Foo\Baz')) {
+ print "Class 'ClassMap\Foo\Bar' exists, although it should not.\n";
+}
+
+// Manually add the class to the APC cache.
+apc_store($key = $prefix . 'ClassMap\Foo\Baz', 'tests/fixtures/src-classmap/classmap-foo-baz.php', 10);
+
+new ClassMap\Foo\Baz;
+
+echo 'SUCCESS';
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/tests/scripts/testrun.php b/core/vendor/donquixote/krautoload/tests/scripts/testrun.php
new file mode 100644
index 0000000..8a32763
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/tests/scripts/testrun.php
@@ -0,0 +1,25 @@
+addClassMap(array(
+ 'ClassMap\Foo\Bar' => 'tests/fixtures/src-classmap/classmap-foo-bar.php',
+ 'ClassMap\Foo\Baz' => 'tests/fixtures/src-classmap/classmap-foo-baz.php',
+));
+$krautoload->addNamespacePSR0('Namespaced2', 'tests/fixtures/src-psr0');
+$krautoload->addPrefixPEAR('Pearlike2', 'tests/fixtures/src-psr0');
+$krautoload->addNamespacePSRX('MyVendor\MyPackage', 'tests/fixtures/src-psrx');
+
+new ClassMap\Foo\Bar;
+new ClassMap\Foo\Baz;
+new Namespaced2\Foo;
+new Pearlike2_Foo;
+new MyVendor\MyPackage\Foo\Bar;
+
+echo 'SUCCESS';
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/tests/src/BootstrapTest.php b/core/vendor/donquixote/krautoload/tests/src/BootstrapTest.php
new file mode 100644
index 0000000..c475fdf
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/tests/src/BootstrapTest.php
@@ -0,0 +1,25 @@
+runTestScript('testrun.php');
+ }
+
+ function testBootstrapApc() {
+ if (extension_loaded('apc') && function_exists('apc_store')) {
+ $this->runTestScript('testrun-apc.php', '-d apc.enable_cli=1');
+ }
+ }
+
+ protected function runTestScript($script, $options = '', $expected = 'SUCCESS') {
+ ob_start();
+ system('php ' . $options . ' tests/scripts/' . $script);
+ $response = ob_get_clean();
+ $this->assertEquals($expected, $response);
+ }
+}
\ No newline at end of file
diff --git a/core/vendor/donquixote/krautoload/tests/src/ClassDiscoveryTest.php b/core/vendor/donquixote/krautoload/tests/src/ClassDiscoveryTest.php
new file mode 100644
index 0000000..378b6a9
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/tests/src/ClassDiscoveryTest.php
@@ -0,0 +1,295 @@
+inspector = new k\NamespaceInspector_Pluggable();
+ $this->hub = new k\RegistrationHub($this->inspector);
+ }
+
+ public function testDiscoveryPSR0() {
+
+ // Register PSR-0 namespace.
+ $dir = $this->getFixturesSubdir('src-psr0');
+ $this->hub->addNamespacePSR0('Namespace_With_Underscore', $dir);
+ $this->hub->addNamespacePSR0('Namespaced', $dir);
+ $this->hub->addNamespacePSR0('Namespaced2', $dir);
+
+ // Build the mock $api object.
+ // We can't use the mock stuff shipped with PHPUnit, because we need a specific order of calls.
+ $api = new k\InjectedAPI_ClassFileVisitor_Mock();
+
+ // Run the discovery.
+ $this->hub->buildSearchableNamespaces(array(
+ 'Namespace_With_Underscore',
+ 'Namespaced',
+ 'Namespace_With_Underscore\Sub_Namespace',
+ ))->apiVisitClassFiles($api, TRUE);
+
+ // Verify the result.
+ $called = $api->mockGetCalled();
+
+ // The InjectedAPI object is being told about the to-be-inspected namespace.
+ $this->assertEquals($called[0], array('setNamespace', array('Namespace_With_Underscore\\')));
+
+ // The two class files for this namespace may be discovered in any order.
+ $this->assertArraySlice($called, 1, 2, array(
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespace_With_Underscore/Sub_Namespace/Foo/BarUnsafe.php',
+ array(
+ // Class names are given relative to the inspected namespace.
+ // There are three class names that could be defined in the file.
+ // They are expected in this exact order.
+ 'Sub_Namespace\Foo\BarUnsafe',
+ 'Sub_Namespace\Foo_BarUnsafe',
+ 'Sub_Namespace_Foo_BarUnsafe',
+ ),
+ ),
+ ),
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespace_With_Underscore/Sub_Namespace/Foo/Bar.php',
+ array(
+ 'Sub_Namespace\Foo\Bar',
+ 'Sub_Namespace\Foo_Bar',
+ 'Sub_Namespace_Foo_Bar',
+ ),
+ ),
+ ),
+ ));
+
+ $this->assertEquals($called[3], array('setNamespace', array('Namespaced\\')));
+
+ // The three class files for this namespace may be discovered in any order.
+ $this->assertArraySlice($called, 4, 3, array(
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespaced/Foo.php',
+ array(
+ 'Foo',
+ ),
+ ),
+ ),
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespaced/Bar.php',
+ array(
+ 'Bar',
+ ),
+ ),
+ ),
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespaced/Baz.php',
+ array(
+ 'Baz',
+ ),
+ ),
+ ),
+ ));
+
+ $this->assertEquals($called[7], array('setNamespace', array('Namespace_With_Underscore\\Sub_Namespace\\')));
+
+ // The two class files for this namespace may be discovered in any order.
+ $this->assertArraySlice($called, 8, 2, array(
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespace_With_Underscore/Sub_Namespace/Foo/BarUnsafe.php',
+ array(
+ 'Foo\BarUnsafe',
+ 'Foo_BarUnsafe',
+ ),
+ ),
+ ),
+ array(
+ 'fileWithClassCandidates',
+ array(
+ $dir . '/Namespace_With_Underscore/Sub_Namespace/Foo/Bar.php',
+ array(
+ 'Foo\Bar',
+ 'Foo_Bar',
+ ),
+ ),
+ ),
+ ));
+ }
+
+ public function testDiscoveryPSRX() {
+
+ // Register PSR-X namespace.
+ $dir = $this->getFixturesSubdir('src-psrx');
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $dir);
+
+ $api = new k\InjectedAPI_ClassFileVisitor_Mock();
+ $this->hub->buildSearchableNamespaces(array('MyVendor\MyPackage'))->apiVisitClassFiles($api, TRUE);
+ $called = $api->mockGetCalled();
+
+ $this->assertEquals($called[0], array('setNamespace', array('MyVendor\MyPackage\\')));
+
+ $this->assertArraySlice($called, 1, 1, array(
+ array(
+ 'fileWithClass',
+ array(
+ $dir . '/Foo/Bar.php',
+ 'Foo\Bar',
+ ),
+ ),
+ ));
+ }
+
+ public function testDiscoveryPSRXChild() {
+
+ // Register PSR-X namespace.
+ $dir = $this->getFixturesSubdir('src-psrx');
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $dir);
+
+ $api = new k\InjectedAPI_ClassFileVisitor_Mock();
+ $this->hub->buildSearchableNamespaces(array('MyVendor\MyPackage\Foo'))->apiVisitClassFiles($api, TRUE);
+ $called = $api->mockGetCalled();
+
+ $this->assertEquals($called[0], array('setNamespace', array('MyVendor\MyPackage\Foo\\')));
+
+ $this->assertArraySlice($called, 1, 1, array(
+ array(
+ 'fileWithClass',
+ array(
+ $dir . '/Foo/Bar.php',
+ 'Bar',
+ ),
+ ),
+ ));
+ }
+
+ public function testDiscoveryPSRXParent() {
+
+ // Register PSR-X namespace.
+ $dir = $this->getFixturesSubdir('src-psrx');
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $dir);
+
+
+ $api = new k\InjectedAPI_ClassFileVisitor_Mock();
+ $this->hub->buildSearchableNamespaces(array('MyVendor'))->apiVisitClassFiles($api, TRUE);
+ $called = $api->mockGetCalled();
+
+ $this->assertEquals($called[0], array('setNamespace', array('MyVendor\\')));
+
+ $this->assertArraySlice($called, 1, 1, array(
+ array(
+ 'fileWithClass',
+ array(
+ $dir . '/Foo/Bar.php',
+ 'MyPackage\Foo\Bar',
+ ),
+ ),
+ ));
+ }
+
+ public function testDiscoveryPSRXRoot() {
+
+ // Register PSR-X namespace.
+ $dir = $this->getFixturesSubdir('src-psrx');
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $dir);
+
+
+ $api = new k\InjectedAPI_ClassFileVisitor_Mock();
+ $this->hub->buildSearchableNamespaces(array(''))->apiVisitClassFiles($api, TRUE);
+ $called = $api->mockGetCalled();
+
+ $this->assertEquals($called[0], array('setNamespace', array('')));
+
+ $this->assertArraySlice($called, 1, 1, array(
+ array(
+ 'fileWithClass',
+ array(
+ $dir . '/Foo/Bar.php',
+ 'MyVendor\MyPackage\Foo\Bar',
+ ),
+ ),
+ ));
+ }
+
+ public function testDiscoverExistingClasses() {
+
+ // Register PSR-0 and PSR-X mappings.
+ $this->hub->addNamespacePSR0('Namespace_With_Underscore', $this->getFixturesSubdir('src-psr0'));
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $this->getFixturesSubdir('src-psrx'));
+
+ // Build SearchableNamespaces object.
+ $namespaces = $this->hub->buildSearchableNamespaces(array('Namespace_With_Underscore'));
+
+ // Search.
+ $classes = $namespaces->discoverExistingClasses(TRUE);
+ $expected = array(
+ 'Namespace_With_Underscore\Sub_Namespace\Foo_Bar',
+ 'Namespace_With_Underscore\Sub_Namespace\Foo_BarUnsafe',
+ );
+ $this->assertArrayElements($classes, array_combine($expected, $expected));
+
+ // Add another namespace (PSR-X)
+ $namespaces->addNamespace('MyVendor');
+
+ // Search again.
+ $classes = $namespaces->discoverExistingClasses(TRUE);
+ $expected[] = 'MyVendor\MyPackage\Foo\Bar';
+ $this->assertArrayElements($classes, array_combine($expected, $expected));
+ }
+
+ public function testClassExistsInNamespace() {
+
+ $this->hub->addNamespacePSR0('Namespace_With_Underscore', $this->getFixturesSubdir('src-psr0'));
+ $namespaces = $this->hub->buildSearchableNamespaces();
+ $this->assertFalse($namespaces->classExistsInNamespaces('Namespace_With_Underscore\Sub_Namespace\Foo_Bar'));
+ $namespaces->addNamespace('Namespace_With_Underscore\Sub_Namespace');
+ $this->assertTrue($namespaces->classExistsInNamespaces('Namespace_With_Underscore\Sub_Namespace\Foo_Bar'));
+ $this->assertTrue($namespaces->classExistsInNamespaces('Namespace_With_Underscore\Sub_Namespace\Foo_Bar'));
+ $namespaces->addNamespace('MyVendor\MyPackage');
+ $this->assertFalse($namespaces->classExistsInNamespaces('MyVendor\MyPackage\Foo\Bar'));
+ }
+
+ protected function assertArraySlice(array $array, $offset, $count, array $compare) {
+ $slice = array_slice($array, $offset, $count);
+ $this->assertArrayElements($slice, $compare);
+ }
+
+ protected function assertArrayElements(array $array, array $compare) {
+ $this->sortBySerializing($array);
+ $this->sortBySerializing($compare);
+ $this->assertEquals($compare, $array);
+ }
+
+ protected function sortBySerializing(array &$array) {
+ $sorted = array();
+ foreach ($array as $item) {
+ $sorted[] = serialize($item);
+ }
+ array_multisort($sorted, $array);
+ }
+
+ protected function getFixturesSubdir($suffix) {
+ return 'tests/fixtures/' . $suffix;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/tests/src/PluggableClassLoaderTest.php b/core/vendor/donquixote/krautoload/tests/src/PluggableClassLoaderTest.php
new file mode 100644
index 0000000..565055b
--- /dev/null
+++ b/core/vendor/donquixote/krautoload/tests/src/PluggableClassLoaderTest.php
@@ -0,0 +1,224 @@
+loader = new k\ClassLoader_Pluggable();
+ $this->hub = new k\RegistrationHub($this->loader);
+ }
+
+ public function testLoadClass() {
+ $this->hub->addClassMap(array(
+ 'ClassMap\Foo\Bar' => $this->getFixturesSubdir('src-classmap') . '/classmap-foo-bar.php',
+ 'ClassMap\Foo\Baz' => $this->getFixturesSubdir('src-classmap') . '/classmap-foo-baz.php',
+ ));
+ $this->hub->addNamespacePSR0('Namespaced2', $this->getFixturesSubdir('src-psr0'));
+ $this->hub->addPrefixPEAR('Pearlike2', $this->getFixturesSubdir('src-psr0'));
+ $this->hub->addNamespacePSRX('MyVendor\MyPackage', $this->getFixturesSubdir('src-psrx'));
+ $this->assertLoadClass('ClassMap\Foo\Bar');
+ $this->assertLoadClass('ClassMap\Foo\Baz');
+ $this->assertLoadClass('Namespaced2\Foo');
+ $this->assertLoadClass('Pearlike2_Foo');
+ $this->assertLoadClass('MyVendor\MyPackage\Foo\Bar');
+ }
+
+ public function testExotic() {
+ $plugin = new k\PrefixPathPlugin_Exotic_CamelSwap();
+ $this->hub->addPrefixPlugin('CamelSwap', $this->getFixturesSubdir('camel-swap'), $plugin);
+ // The class is in tests/fixtures/camel-swap/controller/page/help.php.
+ $this->assertLoadClass('CamelSwap_HelpPageController');
+ }
+
+ public function testUnderscoreSafe() {
+ // Using the paranoid plugin.
+ $this->hub->addNamespacePSR0('Namespace_With_Underscore', $this->getFixturesSubdir('src-psr0'));
+ $this->assertLoadClass('Namespace_With_Underscore\Sub_Namespace\Foo_Bar');
+ // This would break in other class loaders.
+ $this->assertNotLoadClass('Namespace_With_Underscore\Sub_Namespace\Foo\Bar');
+ }
+
+ public function testUnderscoreUnsafe() {
+ // Using the non-paranoid plugin.
+ $plugin = new k\NamespacePathPlugin_ShallowPSR0_NoConflict();
+ $this->hub->addNamespacePlugin('Namespace_With_Underscore', $this->getFixturesSubdir('src-psr0/Namespace_With_Underscore'), $plugin);
+ $this->assertLoadClass('Namespace_With_Underscore\Sub_Namespace\Foo_BarUnsafe');
+ try {
+ $this->assertNotLoadClass('Namespace_With_Underscore\Sub_Namespace\Foo\BarUnsafe');
+ }
+ catch (\Exception $e) {
+ $this->assertEquals($e->getMessage(), 'Cannot redefine class.');
+ return;
+ }
+ $this->fail('The NoConflict loader plugin is expected to break with duplicate class definition.');
+ }
+
+ public function testUseIncludePath() {
+
+ // Register a plugin that can handle include path.
+ $plugin = new k\PrefixPathPlugin_ShallowPEAR_UseIncludePath();
+ $this->hub->addPrefixPlugin('', '', $plugin);
+
+ $this->assertNotLoadClass('Foo', "Class 'Foo' still undefined after ->loadClass() without include path.");
+
+ // Remember original include path.
+ $includePath = get_include_path();
+ set_include_path($this->getFixturesSubdir('includepath') . PATH_SEPARATOR . $includePath);
+
+ $this->loader->loadClass('Foo');
+ $this->assertClassDefined('Foo', "Class 'Foo' successfully loaded after ->loadClass() with include path.");
+
+ // Revert include path to its original value.
+ set_include_path($includePath);
+ }
+
+ /**
+ * @dataProvider getLoadClassFromFallbackTests
+ */
+ public function testLoadClassFromFallback($class, $from = '') {
+ $this->hub->addNamespacePSR0('Namespaced2', $this->getFixturesSubdir('src-psr0'));
+ $this->hub->addPrefixPEAR('Pearlike2', $this->getFixturesSubdir('src-psr0'));
+ // addPrefixPSR0 applies to namespaced and non-namespaced classes.
+ $this->hub->addPrefixPSR0('', $this->getFixturesSubdir('fallback'));
+
+ $this->assertClassUndefined($class);
+ $this->loader->loadClass($class);
+ $this->assertClassDefined($class, "Class '$class' successfully loaded$from.");
+ }
+
+ public function getLoadClassFromFallbackTests() {
+ return array(
+ array('Namespaced2\\Baz'),
+ array('Pearlike2_Baz'),
+ array('Namespaced2\\FooBar', ' from fallback dir'),
+ array('Pearlike2_FooBar', ' from fallback dir'),
+ );
+ }
+
+ /**
+ * @dataProvider getLoadClassNamespaceCollisionTests
+ */
+ public function testLoadClassNamespaceCollision($namespaces, $class, $message) {
+
+ $this->hub->addPrefixesPSR0($namespaces);
+
+ $this->assertClassUndefined($class);
+ $this->loader->loadClass($class);
+ $this->assertClassDefined($class, $message);
+ }
+
+ public function getLoadClassNamespaceCollisionTests() {
+ return array(
+ array(
+ array(
+ 'NamespaceCollision\\C' => $this->getFixturesSubdir('alpha'),
+ 'NamespaceCollision\\C\\B' => $this->getFixturesSubdir('beta'),
+ ),
+ 'NamespaceCollision\C\Foo',
+ '->loadClass() loads NamespaceCollision\C\Foo from alpha.',
+ ),
+ array(
+ array(
+ 'NamespaceCollision\\C\\B' => $this->getFixturesSubdir('beta'),
+ 'NamespaceCollision\\C' => $this->getFixturesSubdir('alpha'),
+ ),
+ 'NamespaceCollision\C\Bar',
+ '->loadClass() loads NamespaceCollision\C\Bar from alpha.',
+ ),
+ array(
+ array(
+ 'NamespaceCollision\\C' => $this->getFixturesSubdir('alpha'),
+ 'NamespaceCollision\\C\\B' => $this->getFixturesSubdir('beta'),
+ ),
+ 'NamespaceCollision\C\B\Foo',
+ '->loadClass() loads NamespaceCollision\C\B\Foo from beta.',
+ ),
+ array(
+ array(
+ 'NamespaceCollision\\C\\B' => $this->getFixturesSubdir('beta'),
+ 'NamespaceCollision\\C' => $this->getFixturesSubdir('alpha'),
+ ),
+ 'NamespaceCollision\C\B\Bar',
+ '->loadClass() loads NamespaceCollision\C\B\Bar from beta.',
+ ),
+ array(
+ array(
+ 'PrefixCollision_C_' => $this->getFixturesSubdir('alpha'),
+ 'PrefixCollision_C_B_' => $this->getFixturesSubdir('beta'),
+ ),
+ 'PrefixCollision_C_Foo',
+ '->loadClass() loads PrefixCollision_C_Foo from alpha.',
+ ),
+ array(
+ array(
+ 'PrefixCollision_C_B_' => $this->getFixturesSubdir('beta'),
+ 'PrefixCollision_C_' => $this->getFixturesSubdir('alpha'),
+ ),
+ 'PrefixCollision_C_Bar',
+ '->loadClass() loads PrefixCollision_C_Bar from alpha.',
+ ),
+ array(
+ array(
+ 'PrefixCollision_C_' => $this->getFixturesSubdir('alpha'),
+ 'PrefixCollision_C_B_' => $this->getFixturesSubdir('beta'),
+ ),
+ 'PrefixCollision_C_B_Foo',
+ '->loadClass() loads PrefixCollision_C_B_Foo from beta.',
+ ),
+ array(
+ array(
+ 'PrefixCollision_C_B_' => $this->getFixturesSubdir('beta'),
+ 'PrefixCollision_C_' => $this->getFixturesSubdir('alpha'),
+ ),
+ 'PrefixCollision_C_B_Bar',
+ '->loadClass() loads PrefixCollision_C_B_Bar from beta.',
+ ),
+ );
+ }
+
+ protected function assertLoadClass($class, $message = NULL) {
+ $this->assertClassUndefined($class);
+ $this->loader->loadClass($class);
+ $this->assertClassDefined($class, $message);
+ }
+
+ protected function assertNotLoadClass($class, $message = NULL) {
+ if (!isset($message)) {
+ $message = "Class '$class' is still undefined after ->loadClass().";
+ }
+ $this->assertClassUndefined($class);
+ $this->loader->loadClass($class);
+ $this->assertClassUndefined($class, $message);
+ }
+
+ protected function assertClassUndefined($class, $message = NULL) {
+ if (!isset($message)) {
+ $message = "Class '$class' is not defined before ->loadClass().";
+ }
+ $this->assertFalse(k\Util::classIsDefined($class), $message);
+ }
+
+ protected function assertClassDefined($class, $message = NULL) {
+ if (!isset($message)) {
+ $message = "Class '$class' was successfully loaded with ->loadClass().";
+ }
+ $this->assertTrue(k\Util::classIsDefined($class), $message);
+ }
+
+ protected function getFixturesSubdir($suffix) {
+ return __DIR__ . '/../fixtures/' . $suffix;
+ }
+}
diff --git a/core/vendor/donquixote/krautoload/trigger-travis.txt b/core/vendor/donquixote/krautoload/trigger-travis.txt
new file mode 100644
index 0000000..e69de29