From 6aeb7e9a3287ccd8bf01596e8825ed880835d014 Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org> Date: Wed, 3 Sep 2014 14:02:51 +0100 Subject: [PATCH] Issue #2325197 by tstoeckler, sun: Remove drupal_classloader(). --- core/includes/bootstrap.inc | 49 ++----------------- core/includes/install.core.inc | 5 +- core/lib/Drupal/Core/DrupalKernel.php | 42 +++++++++------- core/lib/Drupal/Core/Site/Settings.php | 8 ++- .../simpletest/src/InstallerTestBase.php | 5 +- .../modules/simpletest/src/KernelTestBase.php | 3 +- core/modules/simpletest/src/WebTestBase.php | 7 +-- .../Tests/DrupalKernel/DrupalKernelTest.php | 14 ++---- .../System/IgnoreReplicaSubscriberTest.php | 3 +- core/rebuild.php | 2 +- sites/default/default.settings.php | 22 ++++++--- 11 files changed, 68 insertions(+), 92 deletions(-) diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 27494e744b09..8c9603106527 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1024,7 +1024,8 @@ function drupal_bootstrap($phase = NULL) { switch ($current_phase) { case DRUPAL_BOOTSTRAP_CONFIGURATION: - $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod'); + $classloader = require __DIR__ . '/../vendor/autoload.php'; + $kernel = DrupalKernel::createFromRequest($request, $classloader, 'prod'); break; case DRUPAL_BOOTSTRAP_KERNEL: @@ -1398,50 +1399,6 @@ function _current_path($path = NULL) { return $current_path; } -/** - * Initializes and returns the class loader. - * - * The class loader is responsible for lazy-loading all PSR-0 compatible - * classes, interfaces, and traits (PHP 5.4 and later). It's only dependency - * is DRUPAL_ROOT. Otherwise it may be called as early as possible. - * - * @param $class_loader - * The name of class loader to use. This can be used to change the class - * loader class when calling drupal_classloader() from settings.php. It is - * ignored otherwise. - * - * @return \Composer\Autoload\ClassLoader - * A ClassLoader class instance (or extension thereof). - */ -function drupal_classloader($class_loader = NULL) { - // By default, use the ClassLoader which is best for development, as it does - // not break when code is moved on the file system. However, as it is slow, - // allow to use the APC class loader in production. - static $loader; - - if (!isset($loader)) { - - // Retrieve the Composer ClassLoader for loading classes. - $loader = include __DIR__ . '/../vendor/autoload.php'; - - // Register the class loader. - // When configured to use APC, the ApcClassLoader is registered instead. - // Note that ApcClassLoader decorates ClassLoader and only provides the - // findFile() method, but none of the others. The actual registry is still - // in ClassLoader. - if (!isset($class_loader)) { - $class_loader = Settings::get('class_loader', 'default'); - } - if ($class_loader === 'apc') { - require_once __DIR__ . '/../vendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php'; - $apc_loader = new ApcClassLoader('drupal.' . Settings::getHashSalt(), $loader); - $loader->unregister(); - $apc_loader->register(); - } - } - return $loader; -} - /** * Registers an additional namespace. * @@ -1451,7 +1408,7 @@ function drupal_classloader($class_loader = NULL) { * The relative path to the Drupal component in the filesystem. */ function drupal_classloader_register($name, $path) { - $loader = drupal_classloader(); + $loader = \Drupal::service('class_loader'); $loader->addPsr4('Drupal\\' . $name . '\\', DRUPAL_ROOT . '/' . $path . '/src'); } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 8797e74f14e0..f49b5218fe07 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -286,7 +286,8 @@ function install_begin_request(&$install_state) { } $site_path = DrupalKernel::findSitePath($request, FALSE); - Settings::initialize($site_path); + $class_loader = require __DIR__ . '/../vendor/autoload.php'; + Settings::initialize($site_path, $class_loader); // Ensure that procedural dependencies are loaded as early as possible, // since the error/exception handlers depend on them. @@ -358,7 +359,7 @@ function install_begin_request(&$install_state) { } // Only allow dumping the container once the hash salt has been created. - $kernel = InstallerKernel::createFromRequest($request, drupal_classloader(), $environment, (bool) Settings::get('hash_salt', FALSE)); + $kernel = InstallerKernel::createFromRequest($request, $class_loader, $environment, (bool) Settings::get('hash_salt', FALSE)); $kernel->setSitePath($site_path); $kernel->boot(); $container = $kernel->getContainer(); diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index da657c5f708d..7a303a20a5b7 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -182,19 +182,20 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { * Create a DrupalKernel object from a request. * * @param \Symfony\Component\HttpFoundation\Request $request - * @param \Composer\Autoload\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 - * order to be able to find the module serviceProviders. + * The request. + * @param $class_loader + * The class loader. Normally Composer's ClassLoader, as included by the + * front controller, but may also be decorated; e.g., + * \Symfony\Component\ClassLoader\ApcClassLoader. * @param string $environment * String indicating the environment, e.g. 'prod' or 'dev'. * @param bool $allow_dumping * (optional) FALSE to stop the container from being written to or read * from disk. Defaults to TRUE. + * * @return static */ - public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment, $allow_dumping = TRUE) { + public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) { // Include our bootstrap file. require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc'; @@ -204,9 +205,7 @@ public static function createFromRequest(Request $request, ClassLoader $class_lo static::bootEnvironment(); // Get our most basic settings setup. - $site_path = static::findSitePath($request); - $kernel->setSitePath($site_path); - Settings::initialize($site_path); + $kernel->initializeSettings($request); // Redirect the user to the installation script if Drupal has not been // installed yet (i.e., if no $databases array has been defined in the @@ -219,21 +218,32 @@ public static function createFromRequest(Request $request, ClassLoader $class_lo return $kernel; } + /** + * Initializes the kernel's site path and the Settings singleton. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request that will be used to determine the site path. + */ + protected function initializeSettings(Request $request) { + $site_path = static::findSitePath($request); + $this->setSitePath($site_path); + Settings::initialize($site_path, $this->classLoader); + } + /** * Constructs a DrupalKernel object. * * @param string $environment * String indicating the environment, e.g. 'prod' or 'dev'. - * @param \Composer\Autoload\ClassLoader $class_loader - * (optional) The class loader 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 - * order to be able to find the module serviceProviders. + * @param $class_loader + * The class loader. Normally \Composer\Autoload\ClassLoader, as included by + * the front controller, but may also be decorated; e.g., + * \Symfony\Component\ClassLoader\ApcClassLoader. * @param bool $allow_dumping * (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->classLoader = $class_loader; $this->allowDumping = $allow_dumping; @@ -349,8 +359,6 @@ public function boot() { // Start a page timer: Timer::start('page'); - drupal_classloader(); - // Load legacy and other functional code. require_once DRUPAL_ROOT . '/core/includes/common.inc'; require_once DRUPAL_ROOT . '/core/includes/database.inc'; diff --git a/core/lib/Drupal/Core/Site/Settings.php b/core/lib/Drupal/Core/Site/Settings.php index e2d57d2b6e97..def307fd0cbe 100644 --- a/core/lib/Drupal/Core/Site/Settings.php +++ b/core/lib/Drupal/Core/Site/Settings.php @@ -87,8 +87,14 @@ public static function getAll() { * * @param string $site_path * The current site path. + * @param \Composer\Autoload\ClassLoader $class_loader + * The class loader that is used for this request. Passed by reference and + * exposed to the local scope of settings.php, so as to allow it to be + * decorated with Symfony's ApcClassLoader, for example. + * + * @see default.settings.php */ - public static function initialize($site_path) { + public static function initialize($site_path, &$class_loader) { // Export these settings.php variables to the global namespace. global $base_url, $cookie_domain, $config_directories, $config; $settings = array(); diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php index 34354a5aa959..90f318bbdd3a 100644 --- a/core/modules/simpletest/src/InstallerTestBase.php +++ b/core/modules/simpletest/src/InstallerTestBase.php @@ -138,7 +138,8 @@ protected function setUp() { // Import new settings.php written by the installer. $request = Request::createFromGlobals(); - Settings::initialize(DrupalKernel::findSitePath($request)); + $class_loader = require DRUPAL_ROOT . '/core/vendor/autoload.php'; + Settings::initialize(DrupalKernel::findSitePath($request), $class_loader); foreach ($GLOBALS['config_directories'] as $type => $path) { $this->configDirectories[$type] = $path; } @@ -150,7 +151,7 @@ protected function setUp() { // WebTestBase::tearDown() will delete the entire test site directory. // Not using File API; a potential error must trigger a PHP warning. chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777); - $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', FALSE); + $this->kernel = DrupalKernel::createFromRequest($request, $class_loader, 'prod', FALSE); $this->kernel->prepareLegacyRequest($request); $this->container = $this->kernel->getContainer(); $config = $this->container->get('config.factory'); diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php index ea15a3201cf2..4ef5e1097745 100644 --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -155,7 +155,8 @@ protected function setUp() { // Back up settings from TestBase::prepareEnvironment(). $settings = Settings::getAll(); // Bootstrap a new kernel. Don't use createFromRequest so we don't mess with settings. - $this->kernel = new DrupalKernel('testing', drupal_classloader(), FALSE); + $class_loader = require DRUPAL_ROOT . '/core/vendor/autoload.php'; + $this->kernel = new DrupalKernel('testing', $class_loader, FALSE); $request = Request::create('/'); $this->kernel->setSitePath(DrupalKernel::findSitePath($request)); $this->kernel->boot(); diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index c1fe6f70a4f8..e7c1875eb09f 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -861,14 +861,15 @@ protected function setUp() { // Since Drupal is bootstrapped already, install_begin_request() will not // bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to // reload the newly written custom settings.php manually. - Settings::initialize($directory); + $class_loader = require DRUPAL_ROOT . '/core/vendor/autoload.php'; + Settings::initialize($directory, $class_loader); // Execute the non-interactive installer. require_once DRUPAL_ROOT . '/core/includes/install.core.inc'; install_drupal($parameters); // Import new settings.php written by the installer. - Settings::initialize($directory); + Settings::initialize($directory, $class_loader); foreach ($GLOBALS['config_directories'] as $type => $path) { $this->configDirectories[$type] = $path; } @@ -882,7 +883,7 @@ protected function setUp() { chmod($directory, 0777); $request = \Drupal::request(); - $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', TRUE); + $this->kernel = DrupalKernel::createFromRequest($request, $class_loader, 'prod', TRUE); $this->kernel->prepareLegacyRequest($request); // Force the container to be built from scratch instead of loaded from the // disk. This forces us to not accidently load the parent site. diff --git a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php index a36adaebbc3f..a7ac85a8abe2 100644 --- a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php +++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php @@ -9,7 +9,7 @@ use Drupal\Core\DrupalKernel; use Drupal\Core\Site\Settings; -use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\simpletest\KernelTestBase; use Symfony\Component\HttpFoundation\Request; /** @@ -17,12 +17,7 @@ * * @group DrupalKernel */ -class DrupalKernelTest extends DrupalUnitTestBase { - - /** - * @var \Composer\Autoload\ClassLoader - */ - protected $classloader; +class DrupalKernelTest extends KernelTestBase { protected function setUp() { // DrupalKernel relies on global $config_directories and requires those @@ -38,8 +33,6 @@ protected function setUp() { 'directory' => DRUPAL_ROOT . '/' . $this->public_files_directory . '/php', 'secret' => Settings::getHashSalt(), ))); - - $this->classloader = drupal_classloader(); } /** @@ -59,7 +52,8 @@ protected function setUp() { */ protected function getTestKernel(Request $request, array $modules_enabled = NULL, $read_only = FALSE) { // Manually create kernel to avoid replacing settings. - $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'testing'); + $class_loader = require DRUPAL_ROOT . '/core/vendor/autoload.php'; + $kernel = DrupalKernel::createFromRequest($request, $class_loader, 'testing'); $this->settingsSet('hash_salt', $this->databasePrefix); if (isset($modules_enabled)) { $kernel->updateModules($modules_enabled); diff --git a/core/modules/system/src/Tests/System/IgnoreReplicaSubscriberTest.php b/core/modules/system/src/Tests/System/IgnoreReplicaSubscriberTest.php index 49d11ecf81ae..404b8e4b46b4 100644 --- a/core/modules/system/src/Tests/System/IgnoreReplicaSubscriberTest.php +++ b/core/modules/system/src/Tests/System/IgnoreReplicaSubscriberTest.php @@ -32,7 +32,8 @@ function testSystemInitIgnoresSecondaries() { Database::addConnectionInfo('default', 'replica', $connection_info['default']); db_ignore_replica(); - $kernel = new DrupalKernel('testing', drupal_classloader(), FALSE); + $class_loader = require DRUPAL_ROOT . '/core/vendor/autoload.php'; + $kernel = new DrupalKernel('testing', $class_loader, FALSE); $event = new GetResponseEvent($kernel, Request::create('http://example.com'), HttpKernelInterface::MASTER_REQUEST); $subscriber = new ReplicaDatabaseIgnoreSubscriber(); $subscriber->checkReplicaServer($event); diff --git a/core/rebuild.php b/core/rebuild.php index f7acbcea8a7c..c915aff7459e 100644 --- a/core/rebuild.php +++ b/core/rebuild.php @@ -25,7 +25,7 @@ // Manually resemble early bootstrap of DrupalKernel::boot(). require_once __DIR__ . '/includes/bootstrap.inc'; DrupalKernel::bootEnvironment(); -Settings::initialize(DrupalKernel::findSitePath($request)); +Settings::initialize(DrupalKernel::findSitePath($request), $autoloader); if (Settings::get('rebuild_access', FALSE) || ($request->get('token') && $request->get('timestamp') && diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 017fe8ab82c0..3936dcb4630e 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -371,17 +371,23 @@ /** * Class Loader. * - * By default, Drupal uses Composer's ClassLoader, which is best for - * development, as it does not break when code is moved on the file - * system. It is possible, however, to wrap the class loader with a - * cached class loader solution for better performance, which is + * By default, Composer's ClassLoader is used, which is best for development, as + * it does not break when code is moved in the file system. You can decorate the + * class loader with a cached solution for better performance, which is * recommended for production sites. * - * Examples: - * $settings['class_loader'] = 'apc'; - * $settings['class_loader'] = 'default'; + * To do so, you may decorate and replace the local $class_loader variable. + * + * For example, to use Symfony's APC class loader, uncomment the code below. */ -# $settings['class_loader'] = 'apc'; +/* +if ($settings['hash_salt']) { + $apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader('drupal.' . $settings['hash_salt'], $class_loader); + $class_loader->unregister(); + $apc_loader->register(); + $class_loader = $apc_loader; +} +*/ /** * Authorized file system operations: -- GitLab