diff --git a/core/core.services.yml b/core/core.services.yml index da2d413..3a377fc 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: Krautoload\SearchableNamespaces_Default + 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 d9f44da..951fd5f 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2769,9 +2769,8 @@ function drupal_classloader($class_loader = NULL) { if (!isset($loader)) { - // 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 and boot the Krautoload ClassLoader. + require_once DRUPAL_ROOT . '/core/vendor/krautoload/src/Krautoload.php'; // Register the class loader. // When configured to use APC, the ApcClassLoader is registered instead. @@ -2782,21 +2781,18 @@ function drupal_classloader($class_loader = NULL) { $class_loader = 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(); + $salt = 'drupal.' . drupal_get_hash_salt(); + // TODO: Use the salt and boot Krautoload with APC. + $loader = Krautoload::start(); } else { - $loader->register(); + $loader = Krautoload::start(); } // 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); - - // Register the loader with PHP. - $loader->register(); + $loader->composerVendorDir(DRUPAL_ROOT . '/core/vendor'); } + return $loader; } @@ -2810,7 +2806,8 @@ function drupal_classloader($class_loader = NULL) { */ function drupal_classloader_register($name, $path) { $loader = drupal_classloader(); - $loader->addPrefix('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib'); + $loader->addNamespacePSR0('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib'); + $loader->addNamespacePSRX('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/src'); } /** diff --git a/core/includes/common.inc b/core/includes/common.inc index 4829751..3852870 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -8,17 +8,32 @@ use Drupal\Component\Utility\Xss; use Drupal\Core\Cache\Cache; use Drupal\Core\Language\Language; +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Yaml\Parser; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Drupal\Component\PhpStorage\PhpStorageFactory; use Drupal\Component\Utility\MapArray; use Drupal\Component\Utility\NestedArray; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\Core\Database\Database; use Drupal\Core\Routing\GeneratorNotInitializedException; use Drupal\Core\SystemListingInfo; use Drupal\Core\Template\Attribute; +use Zend\Feed\Writer\Writer; +use Zend\Feed\Reader\Reader; + +use Drupal\Core\Asset\CssCollectionRenderer; +use Drupal\Core\Asset\CssCollectionOptimizer; +use Drupal\Core\Asset\CssCollectionGrouper; +use Drupal\Core\Asset\CssOptimizer; +use Drupal\Core\Asset\JsCollectionRenderer; +use Drupal\Core\Asset\JsCollectionOptimizer; +use Drupal\Core\Asset\JsCollectionGrouper; +use Drupal\Core\Asset\AssetDumper; /** * @file @@ -3094,6 +3109,10 @@ function _drupal_bootstrap_code() { // Load all enabled modules Drupal::moduleHandler()->loadAll(); + // Set our bridge extension manager to Zend Feed. + Reader::setExtensionManager(Drupal::service('feed.bridge.reader')); + Writer::setExtensionManager(Drupal::service('feed.bridge.writer')); + // Make sure all stream wrappers are registered. file_get_stream_wrappers(); diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index eefe926..4d0d6da 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -366,6 +366,9 @@ function install_begin_request(&$install_state) { // Add the file translation service to the container. $container->set('string_translator.file_translation', install_file_translation_service()); $container->get('string_translation')->addTranslator($container->get('string_translator.file_translation')); + // Set the request in the kernel to the new created Request above + // so it is available to the rest of the installation process. + $container->set('request', $request); } else { // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. @@ -437,12 +440,8 @@ function install_begin_request(&$install_state) { $container->register('asset.css.collection_renderer', 'Drupal\Core\Asset\CssCollectionRenderer'); $container->register('asset.js.collection_renderer', 'Drupal\Core\Asset\JsCollectionRenderer'); + Drupal::setContainer($container); } - // Set the request in the kernel to the new created Request above - // so it is available to the rest of the installation process. - $container->set('request', $request); - - Drupal::setContainer($container); // Set up $language, so t() caller functions will still work. drupal_language_initialize(); diff --git a/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/AnnotatedClassDiscovery.php index 377bf4a..2021820 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 Krautoload\SearchableNamespaces_Interface as 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,57 +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'); // 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..11efc3b --- /dev/null +++ b/core/lib/Drupal/Component/Plugin/Discovery/ClassFileVisitorAPI.php @@ -0,0 +1,104 @@ +reader = new AnnotationReader(); + // Prevent @endlink from being parsed as an annotation. + $this->reader->addGlobalIgnoredName('endlink'); + $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 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 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, $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; + } + } + + /** + * Extract the annotation from a class. + * + * @param string $file + * @param string $class + */ + 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..6cd37ac 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 Krautoload\SearchableNamespaces_Interface as 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..10b7cf2 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 Krautoload\SearchableNamespaces_Interface as 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/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php index 2897743..f539df7 100644 --- a/core/lib/Drupal/Core/Condition/ConditionManager.php +++ b/core/lib/Drupal/Core/Condition/ConditionManager.php @@ -13,6 +13,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Language\LanguageManager; use Drupal\Core\Plugin\DefaultPluginManager; +use Krautoload\SearchableNamespaces_Interface as SearchableNamespacesInterface; /** * A plugin manager for condition plugins. @@ -22,9 +23,10 @@ class ConditionManager extends DefaultPluginManager implements ExecutableManager /** * Constructs a ConditionManager 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,14 +34,11 @@ class ConditionManager extends DefaultPluginManager implements ExecutableManager * @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) { + public function __construct(SearchableNamespacesInterface $root_namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) { $this->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..0725a7f 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -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 \Krautoload\RegistrationHub $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,8 @@ 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->addNamespacesPSR0($this->getModuleNamespacesPSR0($module_filenames)); + $this->classLoader->addNamespacesPSRX($this->getModuleNamespacesPSRX($module_filenames)); // Load each module's serviceProvider class. foreach ($this->moduleList as $module => $weight) { @@ -417,8 +418,8 @@ 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->addNamespacesPSR0($this->getModuleNamespacesPSR0($container_modules)); + $this->classLoader->addNamespacesPSRX($this->getModuleNamespacesPSRX($container_modules)); // If 'container.modules' is wrong, the container must be rebuilt. if (!isset($this->moduleList)) { @@ -427,13 +428,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 +449,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 +467,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,7 +518,9 @@ 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()); + // The only thing that uses the directories is the annotation discovery, + // which is still on PSR-0 thanks to static methods in doctrine. + $namespaces = $this->getModuleNamespacesPSR0($this->getModuleFileNames()); // Add all components in \Drupal\Core and \Drupal\Component that have a // Plugin directory. foreach (array('Core', 'Component') as $parent_directory) { @@ -518,10 +531,10 @@ protected function buildContainer() { } } } - $container->setParameter('container.namespaces', $namespaces); + $container->setParameter('container.namespaces', array_keys($namespaces)); // Register synthetic services. - $container->register('class_loader', 'Symfony\Component\ClassLoader\ClassLoader')->setSynthetic(TRUE); + $container->register('class_loader', 'Krautoload\RegistrationHub')->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,9 +660,9 @@ protected function getModuleFileNames() { } /** - * Gets the namespaces of each enabled module. + * Gets the PSR-0 namespace directories of each enabled module. */ - protected function getModuleNamespaces($moduleFileNames) { + protected function getModuleNamespacesPSR0($moduleFileNames) { $namespaces = array(); foreach ($moduleFileNames as $module => $filename) { $namespaces["Drupal\\$module"] = DRUPAL_ROOT . '/' . dirname($filename) . '/lib'; @@ -658,9 +671,13 @@ protected function getModuleNamespaces($moduleFileNames) { } /** - * Registers a list of namespaces. + * Gets the PSR-X namespace directories of each enabled module. */ - protected function registerNamespaces(array $namespaces = array()) { - $this->classLoader->addPrefixes($namespaces); + protected function getModuleNamespacesPSRX($moduleFileNames) { + $namespaces = array(); + foreach ($moduleFileNames as $module => $filename) { + $namespaces["Drupal\\$module"] = DRUPAL_ROOT . '/' . dirname($filename) . '/src'; + } + return $namespaces; } } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 4766a91..cd9666b 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 Krautoload\SearchableNamespaces_Interface as 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) { + // Allow the plugin definition to be altered by hook_entity_info_alter(). $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'); $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..07ea7c3 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 Krautoload\SearchableNamespaces_Interface as 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/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 7a1cdac..6c073dc 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 Krautoload\SearchableNamespaces_Interface as 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..34d3579 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 Krautoload\SearchableNamespaces_Interface as 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..19d5ad7 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 Krautoload\SearchableNamespaces_Interface as 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..6c77221 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 Krautoload\SearchableNamespaces_Interface as 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..b0c3cf0 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 Krautoload\SearchableNamespaces_Interface as 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/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php index b21b9f5..a295749 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php @@ -32,8 +32,6 @@ class DefaultParser implements ParserInterface { * {@inheritdoc} */ public function parse(Feed $feed) { - // Set our bridge extension manager to Zend Feed. - Reader::setExtensionManager(\Drupal::service('feed.bridge.reader')); try { $channel = Reader::importString($feed->source_string); } 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..c77c3fc 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 Krautoload\SearchableNamespaces_Interface as 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..caa3108 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 Krautoload\SearchableNamespaces_Interface as 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/comment/lib/Drupal/comment/CommentNewItem.php b/core/modules/comment/lib/Drupal/comment/CommentNewItem.php deleted file mode 100644 index b9dc313..0000000 --- a/core/modules/comment/lib/Drupal/comment/CommentNewItem.php +++ /dev/null @@ -1,41 +0,0 @@ - 'integer', - 'label' => t('Integer value'), - 'class' => '\Drupal\comment\CommentNewValue', - 'computed' => TRUE, - ); - } - return static::$propertyDefinitions; - } -} diff --git a/core/modules/comment/lib/Drupal/comment/CommentNewValue.php b/core/modules/comment/lib/Drupal/comment/CommentNewValue.php deleted file mode 100644 index 1295776..0000000 --- a/core/modules/comment/lib/Drupal/comment/CommentNewValue.php +++ /dev/null @@ -1,44 +0,0 @@ -value)) { - if (!isset($this->parent)) { - throw new InvalidArgumentException('Computed properties require context for computation.'); - } - $field = $this->parent->getParent(); - $entity = $field->getParent(); - $this->value = node_mark($entity->nid->target_id, $entity->changed->value); - } - return $this->value; - } - - /** - * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). - */ - public function setValue($value, $notify = TRUE) { - if (isset($value)) { - throw new ReadOnlyException('Unable to set a computed property.'); - } - } -} diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php index 8cd1a53..4e6ca4c 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php @@ -200,7 +200,7 @@ public function baseFieldDefinitions() { 'description' => t("The comment 'new' marker for the current user (0 read, 1 new, 2 updated)."), 'type' => 'integer_field', 'computed' => TRUE, - 'class' => '\Drupal\comment\CommentNewItem', + 'class' => '\Drupal\comment\FieldNewItem', ); return $properties; } diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewItem.php b/core/modules/comment/lib/Drupal/comment/FieldNewItem.php new file mode 100644 index 0000000..3e23ae7 --- /dev/null +++ b/core/modules/comment/lib/Drupal/comment/FieldNewItem.php @@ -0,0 +1,41 @@ + 'integer', + 'label' => t('Integer value'), + 'class' => '\Drupal\comment\FieldNewValue', + 'computed' => TRUE, + ); + } + return static::$propertyDefinitions; + } +} diff --git a/core/modules/comment/lib/Drupal/comment/FieldNewValue.php b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php new file mode 100644 index 0000000..8f9c392 --- /dev/null +++ b/core/modules/comment/lib/Drupal/comment/FieldNewValue.php @@ -0,0 +1,44 @@ +value)) { + if (!isset($this->parent)) { + throw new InvalidArgumentException('Computed properties require context for computation.'); + } + $field = $this->parent->getParent(); + $entity = $field->getParent(); + $this->value = node_mark($entity->nid->target_id, $entity->changed->value); + } + return $this->value; + } + + /** + * Implements \Drupal\Core\TypedData\TypedDataInterface::setValue(). + */ + public function setValue($value, $notify = TRUE) { + if (isset($value)) { + throw new ReadOnlyException('Unable to set a computed property.'); + } + } +} diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php b/core/modules/edit/lib/Drupal/edit/Plugin/InPlaceEditorManager.php index f4c544b..e031200 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 Krautoload\SearchableNamespaces_Interface as 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..a470a76 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 Krautoload\SearchableNamespaces_Interface as 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 d51544d..3171ce0 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 @@ -14,6 +14,7 @@ use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; use Drupal\Core\Plugin\Discovery\CacheDecorator; use Drupal\entity_reference\Plugin\Type\Selection\SelectionBroken; +use Krautoload\SearchableNamespaces_Interface as SearchableNamespacesInterface; /** * Plugin type manager for the Entity Reference Selection plugin. @@ -23,13 +24,15 @@ class SelectionPluginManager extends PluginManagerBase { /** * Constructs a SelectionPluginManager 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->baseDiscovery = new AlterDecorator(new AnnotatedClassDiscovery('entity_reference/selection', $namespaces), 'entity_reference_selection'); - $this->discovery = new CacheDecorator($this->baseDiscovery, 'entity_reference_selection'); + public function __construct(SearchableNamespacesInterface $root_namespaces) { + $this->discovery = new AnnotatedClassDiscovery($root_namespaces, 'entity_reference\selection'); + $this->discovery = new AlterDecorator($this->discovery, 'entity_reference_selection'); + $this->discovery = new CacheDecorator($this->discovery, 'entity_reference_selection'); $this->factory = new ReflectionFactory($this); } 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 f3cb4cb..40d69ae 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 Krautoload\SearchableNamespaces_Interface as 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..f3aae10 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 Krautoload\SearchableNamespaces_Interface as 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..7a3b556 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 Krautoload\SearchableNamespaces_Interface as 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..8ec84b8 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 Krautoload\SearchableNamespaces_Interface as 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/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php index 44ea1e0..d0fbb8c 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php @@ -661,24 +661,6 @@ function enableMenuLink($item) { } /** - * Test administrative users other than user 1 can access the menu parents AJAX callback. - */ - public function testMenuParentsJsAccess() { - - $admin = $this->drupalCreateUser(array('administer menu')); - $this->drupalLogin($admin); - // Just check access to the callback overall, the POST data is irrelevant. - $this->drupalGetAJAX('admin/structure/menu/parents'); - $this->assertResponse(200); - - // Do standard user tests. - // Login the user. - $this->drupalLogin($this->std_user); - $this->drupalGetAJAX('admin/structure/menu/parents'); - $this->assertResponse(403); - } - - /** * Get standard menu link. */ private function getStandardMenuLink() { diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index af081e5..850feed 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -77,7 +77,7 @@ function menu_menu() { 'title' => 'Parent menu items', 'page callback' => 'menu_parent_options_js', 'type' => MENU_CALLBACK, - 'access arguments' => array('administer menu'), + 'access arguments' => array(TRUE), ); $items['admin/structure/menu/list'] = array( 'title' => 'List menus', diff --git a/core/modules/node/node.module b/core/modules/node/node.module index b04718c..3a1acb4 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -501,6 +501,53 @@ function node_type_update_nodes($old_id, $new_id) { } /** + * Implements hook_rdf_mapping(). + */ +function node_rdf_mapping() { + return array( + array( + 'type' => 'node', + 'bundle' => RDF_DEFAULT_BUNDLE, + 'mapping' => array( + 'rdftype' => array('sioc:Item', 'foaf:Document'), + 'title' => array( + 'predicates' => array('dc:title'), + ), + 'created' => array( + 'predicates' => array('dc:date', 'dc:created'), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'changed' => array( + 'predicates' => array('dc:modified'), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + 'body' => array( + 'predicates' => array('content:encoded'), + ), + 'uid' => array( + 'predicates' => array('sioc:has_creator'), + 'type' => 'rel', + ), + 'name' => array( + 'predicates' => array('foaf:name'), + ), + 'comment_count' => array( + 'predicates' => array('sioc:num_replies'), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => array( + 'predicates' => array('sioc:last_activity_date'), + 'datatype' => 'xsd:dateTime', + 'callback' => 'date_iso8601', + ), + ), + ), + ); +} + +/** * Loads node entities from the database. * * This function should be used whenever you need to load more than one node 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..575b9f2 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 Krautoload\SearchableNamespaces_Interface as 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 5461cab..1f78c25 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -444,38 +444,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,23 +506,14 @@ function simpletest_classloader_register() { $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'); + drupal_classloader()->addNamespacePSR0('Drupal\\' . $name . '\\Tests', DRUPAL_ROOT . '/' . dirname($file->uri) . '/tests'); // 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/', - )); + drupal_classloader()->addNamespacePSR0('Drupal\\Tests', DRUPAL_ROOT . '/core/tests'); } /** diff --git a/core/modules/system/lib/Drupal/system/Form/CronForm.php b/core/modules/system/lib/Drupal/system/Form/CronForm.php index dd83495..c9b91b2 100644 --- a/core/modules/system/lib/Drupal/system/Form/CronForm.php +++ b/core/modules/system/lib/Drupal/system/Form/CronForm.php @@ -9,7 +9,7 @@ use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Config\Context\ContextInterface; -use Drupal\Core\KeyValueStore\KeyValueStoreInterface; +use Drupal\Core\KeyValueStore\KeyValueFactory; use Drupal\system\SystemConfigFormBase; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -36,9 +36,9 @@ class CronForm extends SystemConfigFormBase { * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state * The state key value store. */ - public function __construct(ConfigFactory $config_factory, ContextInterface $context, KeyValueStoreInterface $state) { + public function __construct(ConfigFactory $config_factory, ContextInterface $context, KeyValueFactory $key_value_factory) { parent::__construct($config_factory, $context); - $this->state = $state; + $this->state = $key_value_factory->get('state'); } /** @@ -48,7 +48,7 @@ public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), $container->get('config.context.free'), - $container->get('state') + $container->get('keyvalue') ); } diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php index ddad9c6..a147f39 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 Krautoload\SearchableNamespaces_Interface as 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..f6ffd3e 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 Krautoload\SearchableNamespaces_Interface as 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..28abfe6 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 @@ -57,9 +57,20 @@ 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 finder. + $finder = new \Krautoload\NamespaceVisitor_Pluggable(); + $registrationHub = new \Krautoload\RegistrationHub($finder); + $registrationHub->addNamespacePSR0('Drupal\plugin_test', DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'); + $registrationHub->addNamespacePSR0('Drupal\Component', DRUPAL_ROOT . '/core/lib'); + $registrationHub->addNamespacePSR0('Drupal\Core', DRUPAL_ROOT . '/core/lib'); + + // Build searchable base namespaces. + $root_namespaces = $registrationHub->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..9ad4404 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 @@ -41,13 +41,22 @@ 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 finder. + $finder = new \Krautoload\NamespaceVisitor_Pluggable(); + $registrationHub = new \Krautoload\RegistrationHub($finder); + $registrationHub->addNamespacePSR0('Drupal\plugin_test', DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'); + $registrationHub->addNamespacePSR0('Drupal\Component', DRUPAL_ROOT . '/core/lib'); + $registrationHub->addNamespacePSR0('Drupal\Core', DRUPAL_ROOT . '/core/lib'); + + // Build searchable namespaces. + $root_namespaces = $registrationHub->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..97bc66c 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 Krautoload\SearchableNamespaces_Interface as 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/ManyToOneHelper.php b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php index 08c8cd9..ccd3c3b 100644 --- a/core/modules/views/lib/Drupal/views/ManyToOneHelper.php +++ b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php @@ -37,7 +37,7 @@ public function buildOptionsForm(&$form, &$form_state) { $form['reduce_duplicates'] = array( '#type' => 'checkbox', '#title' => t('Reduce duplicates'), - '#description' => t("This filter can cause items that have more than one of the selected options to appear as duplicate results. If this filter causes duplicate results to occur, this checkbox can reduce those duplicates; however, the more terms it has to search for, the less performant the query will be, so use this with caution. Shouldn't be set on single-value fields, as it may cause values to disappear from display, if used on an incompatible field."), + '#description' => t('This filter can cause items that have more than one of the selected options to appear as duplicate results. If this filter causes duplicate results to occur, this checkbox can reduce those duplicates; however, the more terms it has to search for, the less performant the query will be, so use this with caution. Shouldn\'t be set on single-value fields, as it may cause values to disappear from display, if used on an incompatible field.'), '#default_value' => !empty($this->handler->options['reduce_duplicates']), '#weight' => 4, ); 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..cacf6e4 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 Krautoload\SearchableNamespaces_Interface as 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..228e12d 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 Krautoload\SearchableNamespaces_Interface as 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..b7fe2f0 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 Krautoload\SearchableNamespaces_Interface as 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/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php index 0289031..fda023a 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php @@ -859,10 +859,11 @@ public function buildOptionsForm(&$form, &$form_state) { $this->documentSelfTokens($options[t('Fields')]); // Default text. - $output = '

' . t('You must add some additional fields to this display before using this field. These fields may be marked as Exclude from display if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '

'; + $output = t('

You must add some additional fields to this display before using this field. These fields may be marked as Exclude from display if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.

'); // We have some options, so make a list. if (!empty($options)) { - $output = '

' . t("The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields. If you would like to have the characters '[' and ']' use the html entity codes '%5B' or '%5D' or they will get replaced with empty space.") . '

'; + $output = t('

The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields. +If you would like to have the characters \'[\' and \']\' use the html entity codes \'%5B\' or \'%5D\' or they will get replaced with empty space.

'); foreach (array_keys($options) as $type) { if (!empty($options[$type])) { $items = array(); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/pager/Mini.php b/core/modules/views/lib/Drupal/views/Plugin/views/pager/Mini.php index acd16c0..39db31e 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/pager/Mini.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/pager/Mini.php @@ -57,7 +57,7 @@ public function query() { // Don't query for the next page if we have a pager that has a limited // amount of pages. - if ($this->getItemsPerPage() > 0 && (empty($this->options['total_pages']) || ($this->getCurrentPage() < $this->options['total_pages']))) { + if (empty($this->options['total_pages']) || ($this->getCurrentPage() < $this->options['total_pages'])) { // Increase the items in the query in order to be able to find out whether // there is another page. $limit = $this->view->query->getLimit(); @@ -79,7 +79,7 @@ public function useCountQuery() { public function postExecute(&$result) { // In query() one more item might have been retrieved than necessary. If so, // the next link needs to be displayed and the item removed. - if ($this->getItemsPerPage() > 0 && count($result) > $this->getItemsPerPage()) { + if (count($result) > $this->getItemsPerPage()) { array_pop($result); // Make sure the pager shows the next link by setting the total items to // the biggest possible number but prevent failing calculations like @@ -89,7 +89,7 @@ public function postExecute(&$result) { else { $total = $this->getCurrentPage() * $this->getItemsPerPage() + count($result); } - $this->total_items = $total; + pager_default_initialize($total, $this->getItemsPerPage(), $this->options['id']); } /** diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php index fed8f5a..9994cf5 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/pager/PagerPluginBase.php @@ -183,12 +183,13 @@ public function executeCountQuery(&$count_query) { $this->total_items -= $this->options['offset']; } + $this->updatePageInfo(); return $this->total_items; } /** * If there are pagers that need global values set, this method can - * be used to set them. It will be called after the query is run. + * be used to set them. It will be called when the count query is run. */ public function updatePageInfo() { diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php index 8162b2c..2ba6eb6 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/query/Sql.php @@ -1431,8 +1431,9 @@ function execute(ViewExecutable $view) { } $view->pager->postExecute($view->result); - $view->pager->updatePageInfo(); - $view->total_rows = $view->pager->getTotalItems(); + if ($view->pager->useCountQuery() || !empty($view->get_total_rows)) { + $view->total_rows = $view->pager->getTotalItems(); + } // Load all entities contained in the results. $this->loadEntities($view->result); diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/MiniPagerTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/MiniPagerTest.php index d76bf85..b2accae 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/MiniPagerTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/MiniPagerTest.php @@ -91,13 +91,6 @@ public function testMiniPagerRender() { $this->assertText('‹‹'); $this->assertText($this->nodes[19]->label()); - $this->drupalGet('test_mini_pager_all'); - $this->assertNoText('‹‹ test', 'The previous link does not appear on the page.'); - $this->assertText('Page 1', 'The current page info shows the only page.'); - $this->assertNoText('test ››', 'The next link does not appear on the page.'); - $result = $this->xpath('//div[contains(@class, "views-row")]'); - $this->assertEqual(count($result), count($this->nodes), 'All rows appear on the page.'); - // Remove all items beside 1, so there should be no links shown. for ($i = 0; $i < 19; $i++) { $this->nodes[$i]->delete(); @@ -112,7 +105,7 @@ public function testMiniPagerRender() { $view = views_get_view('test_mini_pager'); $this->executeView($view); $this->assertIdentical($view->get_total_rows, NULL, 'The query was not forced to calculate the total number of results.'); - $this->assertIdentical($view->total_rows, 1, 'The pager calculated the total number of rows.'); + $this->assertIdentical($view->total_rows, NULL, 'The query did not return the total number of rows.'); } } diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml index 484055c..cfc9479 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml @@ -98,19 +98,6 @@ display: type: mini options: items_per_page: '1' - page_3: - display_plugin: page - id: page_3 - display_title: Page - position: '' - display_options: - path: test_mini_pager_all - defaults: - pager: '0' - pager: - type: mini - options: - items_per_page: '0' base_field: nid status: '1' module: views diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php index bfac4e6..9631e38 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/BasicSettingsForm.php @@ -56,7 +56,7 @@ public function buildForm(array $form, array &$form_state) { $form['basic']['ui_show_display_embed'] = array( '#type' => 'checkbox', '#title' => t('Show the embed display in the ui.'), - '#description' => t("Allow advanced user to use the embed view display. The plugin itself works if it's not visible in the ui"), + '#description' => t('Allow advanced user to use the embed view display. The plugin itself works if it\'s not visible in the ui'), '#default_value' => $config->get('ui.show.display_embed'), ); diff --git a/core/vendor/krautoload/LICENSE b/core/vendor/krautoload/LICENSE new file mode 100644 index 0000000..9b3e7af --- /dev/null +++ b/core/vendor/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/krautoload/README.md b/core/vendor/krautoload/README.md new file mode 100644 index 0000000..d8d3534 --- /dev/null +++ b/core/vendor/krautoload/README.md @@ -0,0 +1,88 @@ +Krautoload is a pluggable PHP class autoloader library that makes you fantasize of Kartoffelbrei, Kasseler and Sauerkraut. +It has native support for +- [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) +- Variation of PSR-0 which allows shallow directory structures. +- PEAR (that is the old-school pattern with underscores instead of namespaces) +- Variation of PEAR which allows shallow directory structures. +- 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. + +Besides that, custom plugins can be mapped to any namespaces and prefixes. +This way, you can easily support old-school libraries which don't support any standards, without bloating the SPL autoload stack. + +Krautoload is designed to perform equally well no matter how many namespaces are registered. + + +## Project status and history + +The project is to be considered in "Preview" status. +It should work ok, but API details may still change based on community feedback. +Especially, the term "PSR-X" may change in the future, if it gets accepted. + +A cache layer (APC) basically exist, but is not accessible yet. + +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 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 your feedback. + +```php +require_once "$path_to_krautoload/src/Krautoload.php"; + +// Create the class loader and register it. +$krautoload = Krautoload::start(); + +// Register additional namespaces +$krautoload->namespacePSR0('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); +``` + + +## Unit tests + +Krautoload is designed to be unit-testable, better than other class loaders. +Its architecture allows to mock out and simulate all hits to the filesystem (file_exists(), require_once, etc). + +Unfortunately, I have no experience with testing frameworks outside of Drupal (yet). +Thus, no tests exist yet. +(but there are tests in Drupal xautoload, which show that the architecture is ok) + + +## 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/krautoload/src/Krautoload.php b/core/vendor/krautoload/src/Krautoload.php new file mode 100644 index 0000000..f8bc9d1 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload.php @@ -0,0 +1,46 @@ +register(); + + // 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(); + $finder->registerNamespacePathPlugin('Krautoload/', $basedir . DIRECTORY_SEPARATOR, $plugin); + + // Create the registration hub. + self::$hub = new Krautoload\RegistrationHub($finder); + return self::$hub; + } + + static function registration() { + if (!isset(self::$hub)) { + throw new Exception("Krautoload::start() must run before Krautoload::registration()"); + } + return self::$hub; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassFinder/Interface.php b/core/vendor/krautoload/src/Krautoload/ClassFinder/Interface.php new file mode 100644 index 0000000..e13007d --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassFinder/Interface.php @@ -0,0 +1,37 @@ +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 TRUE|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($api, $class); +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassFinder/Pluggable.php b/core/vendor/krautoload/src/Krautoload/ClassFinder/Pluggable.php new file mode 100644 index 0000000..60ada28 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassFinder/Pluggable.php @@ -0,0 +1,153 @@ +suggestFile($file) method, which returns TRUE if the + // suggested file exists. + // The ->apiFindFile() method is supposed to suggest a number of files + // to the $api, until one is successful, and then return TRUE. Or return + // FALSE, if nothing was found. + if ($this->apiFindFile($api, $class)) { + return TRUE; + } + return FALSE; + } + + /** + * 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 TRUE|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($api, $class) { + + // Discard initial namespace separator. + if ('\\' === $class[0]) { + $class = substr($class, 1); + } + + // First check if the literal class name is registered. + if (!empty($this->classes[$class])) { + foreach ($this->classes[$class] as $file => $skip_class_exists) { + if ($skip_class_exists) { + if ($api->guessFile($file)) { + return TRUE; + } + } + else { + if ($api->guessFileCandidate($file)) { + 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 TRUE|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])) { + 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/krautoload/src/Krautoload/ClassLoader/Abstract.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/Abstract.php new file mode 100644 index 0000000..1ba5274 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/Abstract.php @@ -0,0 +1,38 @@ += 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')); + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcAggressive.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcAggressive.php new file mode 100644 index 0000000..0d931f5 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcAggressive.php @@ -0,0 +1,24 @@ +prefix . $class)) { + apc_store($this->prefix . $class, $file = parent::findFile($class)); + } + + return $file; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcCache.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcCache.php new file mode 100644 index 0000000..66bd423 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/ApcCache.php @@ -0,0 +1,67 @@ +prefix = $prefix; + parent::__construct($finder); + } + + /** + * Set the APC prefix after a flush cache. + * + * @param string $prefix + * A prefix for the storage key in APC. + */ + function setApcPrefix($prefix) { + $this->prefix = $prefix; + } + + /** + * Callback for class loading. This will include ("require") the file found. + * + * @param string $class + * The class to load. + */ + function loadClass($class) { + + if ($file = $this->findFile($class)) { + require $file; + } + } + + /** + * For compatibility, it is possible to use the class loader as a finder. + * + * @param string $class + * The class to find. + * + * @return string + * File where the class is assumed to be. + */ + function findFile($class) { + + if ( + (FALSE === $file = apc_fetch($this->prefix . $class)) || + (!empty($file) && !is_file($file)) + ) { + // Resolve cache miss. + apc_store($this->prefix . $class, $file = parent::findFile($class)); + } + + return $file; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassLoader/Interface.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/Interface.php new file mode 100644 index 0000000..b94b2da --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/Interface.php @@ -0,0 +1,38 @@ +finder = $finder; + } + + /** + * Callback for class loading. This will include ("require") the file found. + * + * @param string $class + * The class to load. + */ + function loadClass($class) { + $api = new InjectedAPI_ClassFinder_LoadClass($class); + // $api has a ->suggestFile($file) method, which returns TRUE if the + // suggested file exists. + // The $finder->findFile() method is supposed to suggest a number of files + // to the $api, until one is successful, and then return TRUE. Or return + // FALSE, if nothing was found. + if ($this->finder->apiFindFile($api, $class)) { + return TRUE; + } + return FALSE; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable.php new file mode 100644 index 0000000..01ce6b2 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable.php @@ -0,0 +1,155 @@ +classes[$class][$file_path] = TRUE; + } + + /** + * Register a plugin for a namespace. + * + * @param string $namespace + * The namespace, e.g. "My\Library" + * @param string $dir + * The deep path, e.g. "../lib/My/Namespace" + * @param FinderPlugin_Interface $plugin + * The plugin. + */ + public function registerNamespacePathPlugin($logicalPath, $dir, $plugin) { + $this->namespaceMap[$logicalPath][$dir] = $plugin; + } + + /** + * Register a plugin for a prefix. + * + * @param string $prefix + * The prefix, e.g. "My_Library" + * @param string $dir + * The deep filesystem location, e.g. "../lib/My/Prefix". + * @param FinderPlugin_Interface $plugin + * The plugin. See + */ + public function registerPrefixPathPlugin($prefix_path_fragment, $dir, $plugin) { + $this->prefixMap[$prefix_path_fragment][$dir] = $plugin; + } + + /** + * Callback for class loading. This will include ("require") the file found. + * + * @param string $class + * The class to load. + */ + function loadClass($class) { + + // Discard initial namespace separator. + if ('\\' === $class[0]) { + $class = substr($class, 1); + } + + // First check if the literal class name is registered. + if (!empty($this->classes[$class])) { + foreach ($this->classes[$class] as $file => $skipClassExists) { + if (is_file($file)) { + if ($skipClassExists) { + // Assume that the file does indeed define the class. + include $file; + return TRUE; + } + else { + // Assume that the file MAY define the class. + include_once $file; + if (class_exists($class, FALSE) || interface_exists($class, FALSE)) { + 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 $logicalBasePath + * First part of the canonical path, with trailing DIRECTORY_SEPARATOR. + * @param string $relativePath + * Second part of the canonical path, ending with '.php'. + * + * @return TRUE|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($map, $class, $logicalBasePath, $relativePath) { + + $path = $logicalBasePath . $relativePath; + while (TRUE) { + // Check any plugin registered for this fragment. + if (!empty($map[$logicalBasePath])) { + 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; + } + } + } +} diff --git a/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php b/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php new file mode 100644 index 0000000..432824b --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/ClassLoader/Pluggable/Interface.php @@ -0,0 +1,51 @@ +nsp = $namespace; + } + + function getNamespace() { + return $this->nsp; + } + + function getClassName($relativeClassName) { + return $this->nsp . $relativeClassName; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php new file mode 100644 index 0000000..a794d30 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectCandidateClasses.php @@ -0,0 +1,22 @@ +classes); + } + + function fileWithClass($file, $relativeClassName) { + $this->classes[$this->getClassName($relativeClassName)] = TRUE; + } + + function fileWithClassCandidates($file, $relativeClassNames) { + foreach ($relativeClassNames as $relativeClassName) { + $this->classes[$this->getClassName($relativeClassName)] = TRUE; + } + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php new file mode 100644 index 0000000..2b264b6 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/CollectExistingClasses.php @@ -0,0 +1,16 @@ +classes; + } + + function confirmedFileWithClass($file, $class) { + $this->classes[$class] = $class; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php new file mode 100644 index 0000000..45c0a3e --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/IncludeEachAbstract.php @@ -0,0 +1,41 @@ +getClassName($relativeClassName), FALSE)) { + $this->confirmedFileWithClass($file, $class); + } + elseif (interface_exists($class, FALSE)) { + $this->confirmedFileWithInterface($file, $class); + } + } + + function fileWithClassCandidates($file, $relativeClassNames) { + include_once $file; + foreach ($relativeClassNames as $relativeClassName) { + // Only find classes, not interfaces. + if (class_exists($class = $this->getClassName($relativeClassName), FALSE)) { + $this->confirmedFileWithClass($file, $class); + } + elseif (interface_exists($class, FALSE)) { + $this->confirmedFileWithInterface($file, $class); + } + } + } + + abstract protected function confirmedFileWithClass($file, $class); + + protected function confirmedFileWithInterface($file, $interface) { + // Do nothing by default. + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php new file mode 100644 index 0000000..39d63ee --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFileVisitor/Interface.php @@ -0,0 +1,14 @@ +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; + } + + /** + * 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. + */ + protected 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; + } + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php new file mode 100644 index 0000000..adf4532 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/CollectFiles.php @@ -0,0 +1,144 @@ +files; + } + + /** + * Suggest a file that, if the file exists, + * HAS TO declare the class we are looking for. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function guessFile($file) { + if (is_file($file)) { + $this->files[$file] = TRUE; + return $file; + } + return FALSE; + } + + /** + * Suggest a file that, if the file exists, + * MAY declare the class we are looking for. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * Always FALSE, because we had no chance to check whether the file actually + * defines the class. + */ + function guessFileCandidate($file) { + if (is_file($file)) { + $this->files[$file] = FALSE; + } + return FALSE; + } + + /** + * Suggest a file that HAS TO declare the class we are looking for. + * + * Unlike guessFile(), claimFile() being called means that the caller is sure + * that the file does exist. Thus, we can skip the is_file() check, saving a + * few nanoseconds. + * + * This is useful if a plugin already did the is_file() check by itself. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * Always TRUE, because further candidates are not interesting. + */ + function claimFile($file) { + $this->files[$file] = TRUE; + return TRUE; + } + + /** + * Suggest a file that MAY declare the class we are looking for. + * + * Unlike guessFile(), claimFile() being called means that the caller is sure + * that the file does exist. Thus, we can skip the is_file() check, saving a + * few nanoseconds. + * + * This is useful if a plugin already did the is_file() check by itself. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * Always FALSE, because we had no chance to check whether the file actually + * defines the class. + */ + function claimFileCandidate($file) { + $this->files[$file] = FALSE; + return FALSE; + } + + /** + * Suggest a file that, if the file exists, + * HAS TO declare the class we are looking for. + * + * Unlike guessFile(), this one checks the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function guessFile_checkIncludePath($file) { + if ($this->fileExistsInIncludePath($file)) { + $this->files[$file] = TRUE; + return TRUE; + } + return FALSE; + } + + /** + * Suggest a file that, if the file exists, + * MAY declare the class we are looking for. + * + * Unlike guessFile(), this one checks the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * Always FALSE, because we had no chance to check whether the file actually + * defines the class. + */ + function guessFileCandidate_checkIncludePath($file) { + if ($this->fileExistsInIncludePath($file)) { + $this->files[$file] = FALSE; + } + return FALSE; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php new file mode 100644 index 0000000..2170393 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/FindExistingClass.php @@ -0,0 +1,115 @@ +fileExistsInIncludePath($file); + } + + /** + * Suggest a file that, if the file exists, + * MAY declare the class we are looking for. + * Include that file, if it exists. + * + * Unlike guessFile(), this one checks the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the file exists and the class exists after file inclusion. + * FALSE, otherwise. + */ + function guessFileCandidate_checkIncludePath($file) { + return $this->fileExistsInIncludePath($file); + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php new file mode 100644 index 0000000..df1e90a --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/ClassFinder/Interface.php @@ -0,0 +1,111 @@ +className, FALSE) || interface_exists($this->className, FALSE); + } + return FALSE; + } + + /** + * Suggest a file that HAS TO declare the class we are looking for. + * Include that file. + * + * Unlike guessFile(), claimFile() being called means that the caller is sure + * that the file does exist. Thus, we can skip the is_file() check, saving a + * few nanoseconds. + * + * This is useful if a plugin already did the is_file() check by itself. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * Always TRUE, because we assume the file does exist and does define the + * class. + */ + function claimFile($file) { + require $file; + return TRUE; + } + + /** + * Suggest a file that MAY declare the class we are looking for. + * Include that file. + * + * Unlike guessFile(), claimFile() being called means that the caller is sure + * that the file does exist. Thus, we can skip the is_file() check, saving a + * few nanoseconds. + * + * This is useful if a plugin already did the is_file() check by itself. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the class exists after file inclusion. + * FALSE, otherwise + */ + function claimFileCandidate($file) { + require_once $file; + return class_exists($this->className, FALSE) || interface_exists($this->className, FALSE); + } + + /** + * Suggest a file that, if the file exists, + * HAS TO declare the class we are looking for. + * Include that file, if it exists. + * + * Unlike guessFile(), this one checks the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the file exists. + * FALSE, otherwise. + */ + function guessFile_checkIncludePath($file) { + if ($this->fileExistsInIncludePath($file)) { + include $file; + return TRUE; + } + return FALSE; + } + + /** + * Suggest a file that, if the file exists, + * MAY declare the class we are looking for. + * Include that file, if it exists. + * + * Unlike guessFile(), this one checks the full PHP include path. + * + * @param string $file + * The file that is supposed to declare the class. + * + * @return boolean + * TRUE, if the file exists and the class exists after file inclusion. + * FALSE, otherwise. + */ + function guessFileCandidate_checkIncludePath($file) { + if ($this->fileExistsInIncludePath($file)) { + include_once $file; + return class_exists($this->className, FALSE) || interface_exists($this->className, FALSE); + } + return FALSE; + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/Interface.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/Interface.php new file mode 100644 index 0000000..0dcbbc4 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/Interface.php @@ -0,0 +1,10 @@ +api = $api; + } + + /** + * @param string $namespace + */ + function setNamespace($namespace) { + $this->api->setNamespace($namespace); + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanNamespace.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanNamespace.php new file mode 100644 index 0000000..5d6ce9a --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanNamespace.php @@ -0,0 +1,10 @@ +pluginScanNamespace($this->api, $baseDir, $relativePath); + } +} diff --git a/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanRecursive.php b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanRecursive.php new file mode 100644 index 0000000..bdb2a44 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/InjectedAPI/NamespaceVisitor/ScanRecursive.php @@ -0,0 +1,10 @@ +pluginScanRecursive($this->api, $baseDir, $relativePath); + } +} diff --git a/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/Interface.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/Interface.php new file mode 100644 index 0000000..de9cd58 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/Interface.php @@ -0,0 +1,46 @@ +getClass() will return the FQCN of the class we are looking for. + * @param string $phyicalBasePath + * 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 $phyicalBasePath + * 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); + + function pluginScanNamespace($api, $baseDir, $relativePath); + + function pluginScanRecursive($api, $baseDir, $relativePath); +} diff --git a/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/LegacyLiteral.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/LegacyLiteral.php new file mode 100644 index 0000000..e69de29 diff --git a/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php new file mode 100644 index 0000000..ae3abe1 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/PSRX.php @@ -0,0 +1,60 @@ +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)) { + 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); + } + } + + protected function doScanRecursive($api, $dir, $relativeNamespace = '') { + 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/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php new file mode 100644 index 0000000..e6a04fb --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0.php @@ -0,0 +1,88 @@ +guessFileCandidate($baseDir . $relativePath)) { + return TRUE; + } + } + + 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; + return class_exists($class, FALSE) || interface_exists($class, FALSE); + } + } + + function pluginScanNamespace($api, $baseDir, $relativePath) { + if (is_dir($dir = $baseDir . $relativePath)) { + 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'))); + } + } + } + } + + function pluginScanRecursive($api, $baseDir, $relativePath) { + if (is_array($baseDir)) { + throw new \Exception("Base dir must not be array."); + } + if (is_array($relativePath)) { + throw new \Exception("Relative path must not be array."); + } + if (is_dir($dir = $baseDir . $relativePath)) { + $this->doScanRecursive($api, $dir); + } + } + + protected function doScanRecursive($api, $dir, $relativeNamespaces = array('\\')) { + 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/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php new file mode 100644 index 0000000..8e83497 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/AllUnderscore.php @@ -0,0 +1,98 @@ +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)) { + 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 = '\\') { + 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/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php new file mode 100644 index 0000000..3ada5d6 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/MapLeak.php @@ -0,0 +1,35 @@ +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/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoConflict.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoConflict.php new file mode 100644 index 0000000..a926dbf --- /dev/null +++ b/core/vendor/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/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php new file mode 100644 index 0000000..a3a4b22 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/NamespacePathPlugin/ShallowPSR0/NoUnderscore.php @@ -0,0 +1,28 @@ +setNamespace($namespace); + + while (TRUE) { + + // Check any plugin registered for this fragment. + if (!empty($this->namespaceMap[$logicalBasePath])) { + 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/krautoload/src/Krautoload/PrefixPathPlugin/Interface.php b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/Interface.php new file mode 100644 index 0000000..fd29b26 --- /dev/null +++ b/core/vendor/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/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR.php b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR.php new file mode 100644 index 0000000..dd1417f --- /dev/null +++ b/core/vendor/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/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php new file mode 100644 index 0000000..4d5f557 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/MapLeak.php @@ -0,0 +1,35 @@ +relativePrefixes[$relativePrefix] = strlen($relativePrefix); + } + + function pluginFindFile($api, $baseDir, $relativePath) { + if ($this->checkPrefix($relativePath)) { + return $api->guessFile($baseDir . $relativePath); + } + } + + function pluginLoadClass($class, $baseDir, $relativePath) { + if ($this->checkPrefix($relativePath)) { + if (is_file($file = $baseDir . $relativePath)) { + include $file; + return TRUE; + } + } + } + + protected function checkPrefix($relativePath) { + foreach ($this->relativePrefixes as $relativePrefix => $length) { + if (!strncmp($relativePath, $relativePrefix, $length) { + return TRUE; + } + } + } +} diff --git a/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php new file mode 100644 index 0000000..d322792 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/PrefixPathPlugin/ShallowPEAR/Uncertain.php @@ -0,0 +1,17 @@ +guessFileCandidate($baseDir . $relativePath); + } + + function pluginLoadClass($class, $baseDir, $relativePath) { + if (is_file($file = $baseDir . $relativePath)) { + include_once $file; + return class_exists($class, FALSE) || interface_exists($class, FALSE); + } + } +} diff --git a/core/vendor/krautoload/src/Krautoload/RegistrationHub.php b/core/vendor/krautoload/src/Krautoload/RegistrationHub.php new file mode 100644 index 0000000..2f07caa --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/RegistrationHub.php @@ -0,0 +1,253 @@ +finder = $finder; + $this->plugins['ShallowPEAR'] = new PrefixPathPlugin_ShallowPEAR(); + $this->plugins['ShallowPSR0'] = new NamespacePathPlugin_ShallowPSR0(); + $this->plugins['PSRX'] = new NamespacePathPlugin_PSRX(); + } + + function getFinder() { + return $this->finder; + } + + /** + * @param callback $callback + * Registration callback, which takes as an argument the registration hub. + */ + function krautoloadCallback($callback) { + call_user_func($callback, $this); + } + + /** + * @param string $file + * Path to a PHP file that, on inclusion, returns a registration callback. + */ + function krautoloadFile($file) { + $callback = require $file; + call_user_func($callback, $this); + } + + /** + * @param string $dir + * Vendor directory of a project using composer. + * This allows to use Krautoload for composer-based PHP projects. + */ + 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'; + foreach ($class_map as $class => $file) { + $this->finder->registerClass($class, $file); + } + } + } + + /** + * Adds prefixes. + * + * @param array $prefixes + * Prefixes to add + */ + function addPrefixesPSR0(array $prefixes) { + foreach ($prefixes as $prefix => $rootDirs) { + $this->addPrefixPSR0($prefix, $rootDirs); + } + } + + /** + * Registers a set of classes + * + * @param string $prefix + * The classes prefix + * @param array|string $rootDirs + * The location(s) of the classes + */ + function addPrefixPSR0($prefix, $rootDirs) { + + if (!$prefix) { + // We consider this as a "fallback". + } + elseif ('\\' === substr($prefix, -1)) { + // We assume that $prefix is meant as a namespace, + // and the paths are PSR-0 directories. + $namespace = substr($prefix, 0, -1); + foreach ((array) $rootDirs as $rootDir) { + $this->addNamespacePSR0($namespace, $rootDir); + } + } + elseif (FALSE !== strrpos($prefix, '\\')) { + // We assume that $prefix is meant as a namespace, + // and the paths are PSR-0 directories. + $namespace = $prefix; + foreach ((array) $rootDirs as $rootDir) { + $this->addNamespacePSR0($namespace, $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. + foreach ((array) $rootDirs as $rootDir) { + $this->addPrefixPEAR(substr($prefix, 0, -1), $rootDir); + } + // 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. + foreach ((array) $rootDirs as $rootDir) { + $this->addNamespacePSR0($prefix, $rootDir); + $this->addPrefixPEAR($prefix, $rootDir); + $this->addClassFile($prefix, $rootDir . '.php'); + } + // TODO: + // Register special plugins to cover other FQCNs + // that happen to begin with with the prefix. + } + } + + function addNamespacesPSR0($namespaces) { + foreach ($namespaces as $namespace => $rootDirs) { + $this->addNamespacePSR0($namespace, $rootDirs); + } + } + + function addNamespacePSR0($namespace, $rootDirs) { + if (empty($namespace)) { + foreach ((array) $rootDirs as $rootDir) { + $rootDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : ''; + $this->finder->registerNamespacePathPlugin('', $rootDir, $this->plugins['ShallowPSR0']); + $this->finder->registerPrefixPathPlugin('', $rootDir, $this->plugins['ShallowPEAR']); + } + } + else { + $logicalBasePath = $this->namespaceLogicalPath($namespace); + foreach ((array) $rootDirs as $rootDir) { + $baseDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : ''; + $baseDir .= $logicalBasePath; + $this->finder->registerNamespacePathPlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPSR0']); + } + } + } + + function addNamespacesShallowPSR0($namespaces) { + foreach ($namespaces as $namespace => $baseDirs) { + $this->addNamespaceShallowPSR0($namespace, $baseDirs); + } + } + + function addNamespaceShallowPSR0($namespace, $baseDirs) { + $logicalBasePath = $this->namespaceLogicalPath($namespace); + foreach ((array) $baseDirs as $baseDir) { + $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : ''; + $this->finder->registerNamespacePathPlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPSR0']); + } + } + + function addPrefixesPEAR($prefixes) { + foreach ($prefixes as $prefix => $rootDirs) { + $this->addPrefixPEAR($prefix, $rootDirs); + } + } + + function addPrefixPEAR($prefix, $rootDirs) { + $logicalBasePath = $this->prefixLogicalPath($prefix); + foreach ((array) $rootDirs as $rootDir) { + $baseDir = strlen($rootDir) ? $rootDir . DIRECTORY_SEPARATOR : ''; + $baseDir .= $logicalBasePath; + $this->finder->registerPrefixPathPlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPEAR']); + } + } + + function addPrefixesShallowPEAR($prefixes) { + foreach ($prefixes as $prefix => $baseDirs) { + $this->addPrefixPEAR($prefix, $baseDirs); + } + } + + function addPrefixShallowPEAR($prefix, $baseDirs) { + $logicalBasePath = $this->prefixLogicalPath($prefix); + foreach ((array) $baseDirs as $baseDir) { + $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : ''; + $this->finder->registerPrefixPathPlugin($logicalBasePath, $baseDir, $this->plugins['ShallowPEAR']); + } + } + + function addNamespacesPSRX($namespaces) { + foreach ($namespaces as $namespace => $baseDirs) { + $this->addNamespacePSRX($namespace, $baseDirs); + } + } + + function addNamespacePSRX($namespace, $baseDirs) { + $logicalBasePath = $this->namespaceLogicalPath($namespace); + foreach ((array) $baseDirs as $baseDir) { + $baseDir = strlen($baseDir) ? $baseDir . DIRECTORY_SEPARATOR : ''; + $this->finder->registerNamespacePathPlugin($logicalBasePath, $baseDir, $this->plugins['PSRX']); + } + } + + function addClassFile($class, $file) { + $this->finder->registerClass($class, $file); + } + + function buildSearchableNamespaces($namespaces = array()) { + $searchable = new SearchableNamespaces_Default($this->finder); + $searchable->addNamespaces($namespaces); + return $searchable; + } + + /** + * 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/krautoload/src/Krautoload/SearchableNamespaces/Default.php b/core/vendor/krautoload/src/Krautoload/SearchableNamespaces/Default.php new file mode 100644 index 0000000..ebe9158 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/SearchableNamespaces/Default.php @@ -0,0 +1,185 @@ +finder = $finder; + } + + /** + * @param NamespaceVisitor_Interface $finder + * @todo This should be a more universal interface.. + */ + function setFinder(NamespaceVisitor_Interface $finder) { + $this->finder = $finder; + } + + /** + * Add a namespace. + * + * @param string $namespace + */ + function addNamespace($namespace) { + $this->namespaces[$namespace] = $namespace; + } + + /** + * Set namespaces. + * + * @param array $namespaces + */ + function setNamespaces(array $namespaces) { + $this->namespaces = array(); + $this->addNamespaces($namespaces); + } + + /** + * Add namespaces. + * + * @param array $namespaces + */ + function addNamespaces(array $namespaces) { + foreach ($namespaces as $namespace) { + $this->namespaces[$namespace] = $namespace; + } + } + + /** + * Get namespaces. + * + * @param array $namespaces + */ + function getNamespaces() { + return $this->namespaces; + } + + /** + * @param array $namespaces + * Namespaces for the new family. + * + * @return SearchableNamespaces_Interface + * Newly created namespace family. + */ + function buildSearchableNamespaces(array $namespaces = array()) { + $new = new self($this->finder); + $new->addNamespaces($namespaces); + return $new; + } + + /** + * @param string $suffix + * Namespace suffix to append to each namespace. + * + * @return SearchableNamespaces_Interface + * Newly created namespace family. + */ + function buildFromSuffix($suffix) { + if ('\\' !== $suffix[0]) { + $suffix = '\\' . $suffix; + } + $new = $this->buildSearchableNamespaces(); + foreach ($this->namespaces as $namespace) { + $new->addNamespace($namespace . $suffix); + } + return $new; + } + + /** + * Scan all registered namespaces for classes. + * Tell the $api object about each class file that is found. + * + * @param InjectedAPI_ClassFileVisitor_Interface $api + * @param boolean $recursive + */ + function apiVisitClassFiles(InjectedAPI_ClassFileVisitor_Interface $api, $recursive = FALSE) { + $namespaceVisitorAPI = $recursive ? new InjectedAPI_NamespaceVisitor_ScanRecursive($api) : new InjectedAPI_NamespaceVisitor_ScanNamespace($api); + $this->apiVisitNamespaces($namespaceVisitorAPI); + } + + /** + * Visit all namespaces. + * + * @param InjectedAPI_NamespaceVisitor_Interface $api + */ + function apiVisitNamespaces(InjectedAPI_NamespaceVisitor_Interface $api) { + foreach ($this->namespaces as $namespace) { + $this->finder->apiFindNamespace($api, $namespace); + } + } + + /** + * Scan all registered namespaces for class files, include each file, and + * return all classes that actually exist (but no interfaces). + * + * @param boolean $recursive + * + * @return array + * Collected class names. + */ + function discoverExistingClasses($recursive = FALSE) { + $api = new InjectedAPI_ClassFileVisitor_CollectExistingClasses(); + $this->apiVisitClassFiles($api, $recursive); + return $api->getCollectedClasses(); + } + + /** + * Scan all registered namespaces for class files, and return all names that + * may be defined as a class or interface within these namespaces. + * + * @param boolean $recursive + * + * @return array + * Collected class names. + */ + function discoverCandidateClasses($recursive = FALSE) { + $api = new InjectedAPI_ClassFileVisitor_CollectCandidateClasses(); + $this->apiVisitClassFiles($api, $recursive); + return $api->getCollectedClasses(); + } + + /** + * Check if the given class is "known", and load it. + * This will check the following: + * - Is the class within any of the registered namespaces? + * - Is there is a file for this class, within the registered directories? + * (Include that file, if it exists.) + * - Is the class defined after file inclusion? + * + * The method can return FALSE even if the class is defined + * + * @param string $class + */ + 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/krautoload/src/Krautoload/SearchableNamespaces/Interface.php b/core/vendor/krautoload/src/Krautoload/SearchableNamespaces/Interface.php new file mode 100644 index 0000000..1f380d0 --- /dev/null +++ b/core/vendor/krautoload/src/Krautoload/SearchableNamespaces/Interface.php @@ -0,0 +1,98 @@ + $item) { + if ($item['function'] === 'spl_autoload_call') { + switch ($f = $trace[$i + 1]['function']) { + case 'class_exists': + case 'interface_exists': + case 'method_exists': + case 'is_callable': + // @todo Add more cases. + return TRUE; + default: + return FALSE; + } + } + } + } + + static function classIsDefined($class) { + return class_exists($class, FALSE) || interface_exists($class, FALSE); + } +}