diff --git a/composer.json b/composer.json index e4f74e0dc807275ab28bfba28f87b39419f4da05..9db48262376a2db549b4a01c52373294a26cbef9 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,13 @@ "easyrdf/easyrdf": "0.8.0-beta.1", "phpunit/phpunit": "3.7.15" }, + "autoload": { + "psr-0": { + "Drupal\\Core": "core/lib/", + "Drupal\\Component": "core/lib/", + "Drupal\\Driver": "drivers/lib/" + } + }, "minimum-stability": "dev", "config": { "vendor-dir": "core/vendor" diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index e8ccd368a04e05f67d77a1ec4e9709ac07c5354a..c14ab53215995a4bbc13ca2e03044cb1d5bd24db 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -6,8 +6,8 @@ use Drupal\Core\DrupalKernel; use Drupal\Core\Database\Database; use Drupal\Core\DependencyInjection\ContainerBuilder; -use Symfony\Component\ClassLoader\UniversalClassLoader; -use Symfony\Component\ClassLoader\ApcUniversalClassLoader; +use Symfony\Component\ClassLoader\ClassLoader; +use Symfony\Component\ClassLoader\ApcClassLoader; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Reference; @@ -3076,78 +3076,41 @@ function ip_address() { * loader class when calling drupal_classloader() from settings.php. It is * ignored otherwise. * - * @return Symfony\Component\ClassLoader\UniversalClassLoader - * A UniversalClassLoader class instance (or extension thereof). + * @return \Symfony\Component\ClassLoader\ClassLoader + * A ClassLoader class instance (or extension thereof). */ function drupal_classloader($class_loader = NULL) { - // By default, use the UniversalClassLoader which is best for development, - // as it does not break when code is moved on the file system. However, as it - // is slow, allow to use the APC class loader in production. + // By default, use the ClassLoader which is best for development, as it does + // not break when code is moved on the file system. However, as it is slow, + // allow to use the APC class loader in production. static $loader; 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/UniversalClassLoader.php'; - if (!isset($class_loader) && class_exists('Drupal\Component\Utility\Settings', FALSE)) { - $class_loader = settings()->get('class_loader'); + require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassLoader.php'; + $loader = new ClassLoader(); + + // Register the class loader. + // When configured to use APC, the ApcClassLoader is registered instead. + // Note that ApcClassLoader decorates ClassLoader and only provides the + // findFile() method, but none of the others. The actual registry is still + // in ClassLoader. + if (!isset($class_loader)) { + $class_loader = settings()->get('class_loader', 'default'); } - - switch ($class_loader) { - case 'apc': - if (function_exists('apc_store')) { - require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php'; - $loader = new ApcUniversalClassLoader('drupal.' . $GLOBALS['drupal_hash_salt']); - break; - } - // Fall through to the default loader if APC was not loaded, so that the - // site does not fail completely. - case 'dev': - case 'default': - default: - $loader = new UniversalClassLoader(); - break; + if ($class_loader === 'apc') { + require_once DRUPAL_ROOT . '/core/vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php'; + $apc_loader = new ApcClassLoader('drupal.' . $GLOBALS['drupal_hash_salt'], $loader); + $apc_loader->register(); + } + else { + $loader->register(); } - // Register explicit namespaces for Drupal core. - // The majority of namespaces that need to be resolved are from Drupal core, - // so registering/setting them before vendor libraries saves a few - // additional cycles per class lookup. - $loader->registerNamespaces(array( - 'Drupal\Core' => DRUPAL_ROOT . '/core/lib', - 'Drupal\Component' => DRUPAL_ROOT . '/core/lib', - 'Drupal\Driver' => DRUPAL_ROOT . '/drivers/lib', - )); - - // Register namespaces and PEAR-like prefixes for vendor libraries managed - // by Composer. Composer combines libraries that use PHP 5.3 namespaces and - // ones that use PEAR-like class prefixes in a single array, but the Symfony - // class loader requires them to be registered separately. + // Register namespaces for vendor libraries managed by Composer. $prefixes_and_namespaces = require DRUPAL_ROOT . '/core/vendor/composer/autoload_namespaces.php'; - $prefixes = array(); - $namespaces = array(); - foreach ($prefixes_and_namespaces as $key => $path) { - // If the key: - // - Contains a namespace separator, we know it's a namespace. - // - Doesn't contain a namespace separator and ends in an "_" (e.g., - // "Twig_"), it's likely intended as a PEAR-like prefix rather than a - // namespace. - // - Doesn't contain a namespace separator or end in an "_" (e.g., - // "Assetic"), then it could be either a namespace or an incomplete - // PEAR-like prefix, but we assume the former, since the only example of - // that currently in Drupal is Assetic. - // @todo Switch to a class loader that doesn't require this guessing: - // http://drupal.org/node/1658720. - $is_namespace = (strpos($key, '\\') !== FALSE) && (substr($key, -1) !== '_'); - if ($is_namespace) { - $namespaces[rtrim($key, '\\')] = $path; - } - else { - $prefixes[$key] = $path; - } - } - $loader->registerPrefixes($prefixes); - $loader->registerNamespaces($namespaces); + $loader->addPrefixes($prefixes_and_namespaces); // Register the loader with PHP. $loader->register(); @@ -3165,7 +3128,7 @@ function drupal_classloader($class_loader = NULL) { */ function drupal_classloader_register($name, $path) { $loader = drupal_classloader(); - $loader->registerNamespace('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib'); + $loader->addPrefix('Drupal\\' . $name, DRUPAL_ROOT . '/' . $path . '/lib'); } /** diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index ee14fb37f07a1bb6bf5bce6114c22c8a7e204828..6a26314fde5627eb13a1f500aad1edb1606d7d42 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -11,7 +11,7 @@ use Drupal\Core\Config\BootstrapConfigStorageFactory; use Drupal\Core\CoreBundle; use Drupal\Core\DependencyInjection\ContainerBuilder; -use Symfony\Component\ClassLoader\UniversalClassLoader; +use Symfony\Component\ClassLoader\ClassLoader; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; @@ -67,7 +67,7 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { /** * The classloader object. * - * @var \Symfony\Component\ClassLoader\UniversalClassLoader + * @var \Symfony\Component\ClassLoader\ClassLoader */ protected $classLoader; @@ -110,7 +110,7 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { * Boolean indicating whether we are in debug mode. Used by * Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use * this value currently. Pass TRUE. - * @param \Symfony\Component\ClassLoader\UniversalClassLoader $class_loader + * @param \Symfony\Component\ClassLoader\ClassLoader $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 @@ -119,7 +119,7 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { * (optional) FALSE to stop the container from being written to or read * from disk. Defaults to TRUE. */ - public function __construct($environment, $debug, UniversalClassLoader $class_loader, $allow_dumping = TRUE) { + public function __construct($environment, $debug, ClassLoader $class_loader, $allow_dumping = TRUE) { parent::__construct($environment, $debug); $this->classLoader = $class_loader; $this->allowDumping = $allow_dumping; @@ -294,7 +294,7 @@ protected function initializeContainer() { // All namespaces must be registered before we attempt to use any service // from the container. $container_modules = $this->container->getParameter('container.modules'); - $namespaces_before = $this->classLoader->getNamespaces(); + $namespaces_before = $this->classLoader->getPrefixes(); $this->registerNamespaces($this->getModuleNamespaces($container_modules)); // If 'container.modules' is wrong, the container must be rebuilt. @@ -308,9 +308,9 @@ protected function initializeContainer() { // registerNamespaces() performs a merge rather than replace, so to // effectively remove erroneous registrations, we must replace them with // empty arrays. - $namespaces_after = $this->classLoader->getNamespaces(); + $namespaces_after = $this->classLoader->getPrefixes(); $namespaces_before += array_fill_keys(array_diff(array_keys($namespaces_after), array_keys($namespaces_before)), array()); - $this->classLoader->registerNamespaces($namespaces_before); + $this->registerNamespaces($namespaces_before); } } @@ -376,7 +376,7 @@ protected function buildContainer() { $container->setParameter('container.namespaces', $namespaces); // Register synthetic services. - $container->register('class_loader', 'Symfony\Component\ClassLoader\UniversalClassLoader')->setSynthetic(TRUE); + $container->register('class_loader', 'Symfony\Component\ClassLoader\ClassLoader')->setSynthetic(TRUE); $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE); $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE); foreach ($this->bundles as $bundle) { @@ -474,8 +474,6 @@ protected function getModuleNamespaces($moduleFileNames) { * Registers a list of namespaces. */ protected function registerNamespaces(array $namespaces = array()) { - foreach ($namespaces as $namespace => $dir) { - $this->classLoader->registerNamespace($namespace, $dir); - } + $this->classLoader->addPrefixes($namespaces); } } diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index b78ff3ccd647dd5dcf05d76dbf9924fc8957c04b..5ad1b393539f186aed4383cde2e03b5b3f18e702 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -526,19 +526,19 @@ 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()->registerNamespace('Drupal\\' . $name . '\\Tests', DRUPAL_ROOT . '/' . dirname($file->uri) . '/tests'); + drupal_classloader()->addPrefix('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()->registerNamespace('Drupal\\Tests', DRUPAL_ROOT . '/core/tests'); + 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()->registerPrefixes(array( + 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/', 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 df59ea08d8aae98d7a992c536f9676896deeb85e..2fd8eb93432ac29a1e470f8f2f0befa6edfc05eb 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Module/ClassLoaderTest.php @@ -13,6 +13,12 @@ * Tests class loading. */ class ClassLoaderTest extends WebTestBase { + + /** + * The expected result from calling the module-provided class' method. + */ + protected $expected = 'Drupal\\module_autoload_test\\SomeClass::testMethod() was invoked.'; + public static function getInfo() { return array( 'name' => 'Module class loader', @@ -23,24 +29,33 @@ public static function getInfo() { /** * Tests that module-provided classes can be loaded when a module is enabled. + * + * @see \Drupal\module_autoload_test\SomeClass */ function testClassLoading() { - $expected = 'Drupal\\module_autoload_test\\SomeClass::testMethod() was invoked.'; - + // Enable the module_test and module_autoload_test modules. module_enable(array('module_test', 'module_autoload_test'), FALSE); $this->resetAll(); // Check twice to test an unprimed and primed system_list() cache. for ($i=0; $i<2; $i++) { $this->drupalGet('module-test/class-loading'); - $this->assertText($expected, 'Autoloader loads classes from an enabled module.'); + $this->assertText($this->expected, 'Autoloader loads classes from an enabled module.'); } + } + /** + * Tests that module-provided classes can't be loaded from disabled modules. + * + * @see \Drupal\module_autoload_test\SomeClass + */ + function testClassLoadingDisabledModules() { + // Ensure that module_autoload_test is disabled. module_disable(array('module_autoload_test'), FALSE); $this->resetAll(); // Check twice to test an unprimed and primed system_list() cache. for ($i=0; $i<2; $i++) { $this->drupalGet('module-test/class-loading'); - $this->assertNoText($expected, 'Autoloader does not load classes from a disabled module.'); + $this->assertNoText($this->expected, 'Autoloader does not load classes from a disabled module.'); } } } diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php index 54b2551e7bcff6026d85e2320fe922b17007137f..3d8eaaf67ac989331729dd2fb00da3d356b81b90 100644 --- a/core/vendor/composer/autoload_namespaces.php +++ b/core/vendor/composer/autoload_namespaces.php @@ -6,6 +6,9 @@ $baseDir = dirname($vendorDir); return array( + 'Drupal\\Driver' => $baseDir . '/../drivers/lib/', + 'Drupal\\Core' => $baseDir . '/lib/', + 'Drupal\\Component' => $baseDir . '/lib/', 'Twig_' => $vendorDir . '/twig/twig/lib/', 'Symfony\\Component\\Yaml\\' => $vendorDir . '/symfony/yaml/', 'Symfony\\Component\\Validator\\' => $vendorDir . '/symfony/validator/',