Commit 92ecd3b9 authored by catch's avatar catch
Browse files

Issue #3020296 by alexpott, longwave, bradjones1, catch, Berdir, gapple:...

Issue #3020296 by alexpott, longwave, bradjones1, catch, Berdir, gapple: Remove Symfony's classloader as it does not exist in Symfony 4
parent 3e7619bd
......@@ -457,7 +457,7 @@
"dist": {
"type": "path",
"url": "core",
"reference": "66032fab56e4ed2421480c8343f8c86f7db8a18f"
"reference": "f8e50d64acdddb816b10f83ca307712bd2cd65e5"
},
"require": {
"asm89/stack-cors": "^1.1",
......@@ -487,7 +487,6 @@
"psr/log": "^1.0",
"stack/builder": "^1.0",
"symfony-cmf/routing": "^2.1",
"symfony/class-loader": "~3.4.0",
"symfony/console": "^4.4",
"symfony/dependency-injection": "^4.4",
"symfony/event-dispatcher": "^4.4",
......@@ -660,11 +659,29 @@
},
"classmap": [
"lib/Drupal.php",
"lib/Drupal/Component/DependencyInjection/Container.php",
"lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php",
"lib/Drupal/Component/FileCache/FileCacheFactory.php",
"lib/Drupal/Component/Utility/Timer.php",
"lib/Drupal/Component/Utility/Unicode.php",
"lib/Drupal/Core/Cache/Cache.php",
"lib/Drupal/Core/Cache/CacheBackendInterface.php",
"lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php",
"lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php",
"lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php",
"lib/Drupal/Core/Cache/DatabaseBackend.php",
"lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php",
"lib/Drupal/Core/Database/Connection.php",
"lib/Drupal/Core/Database/Database.php",
"lib/Drupal/Core/Database/Driver/mysql/Connection.php",
"lib/Drupal/Core/Database/Driver/pgsql/Connection.php",
"lib/Drupal/Core/Database/Driver/sqlite/Connection.php",
"lib/Drupal/Core/Database/Statement.php",
"lib/Drupal/Core/Database/StatementInterface.php",
"lib/Drupal/Core/DependencyInjection/Container.php",
"lib/Drupal/Core/DrupalKernel.php",
"lib/Drupal/Core/DrupalKernelInterface.php",
"lib/Drupal/Core/Installer/InstallerRedirectTrait.php",
"lib/Drupal/Core/Site/Settings.php"
]
},
......@@ -1916,62 +1933,6 @@
],
"time": "2019-12-10T10:41:58+00:00"
},
{
"name": "symfony/class-loader",
"version": "v3.4.37",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
"reference": "bcdf6ff46e115b29be3186391f29e0da82cd6f72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/bcdf6ff46e115b29be3186391f29e0da82cd6f72",
"reference": "bcdf6ff46e115b29be3186391f29e0da82cd6f72",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
"require-dev": {
"symfony/finder": "~2.8|~3.0|~4.0",
"symfony/polyfill-apcu": "~1.1"
},
"suggest": {
"symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\ClassLoader\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
"time": "2020-01-04T12:05:51+00:00"
},
{
"name": "symfony/console",
"version": "v4.4.4",
......@@ -4101,9 +4062,6 @@
"ext-zip": "Enabling the zip extension allows you to unzip archives",
"ext-zlib": "Allow gzip compression of HTTP requests"
},
"bin": [
"bin/composer"
],
"type": "library",
"extra": {
"branch-alias": {
......
......@@ -35,7 +35,6 @@
"ralouphie/getallheaders": "3.0.3",
"stack/builder": "v1.0.6",
"symfony-cmf/routing": "2.1.1",
"symfony/class-loader": "v3.4.37",
"symfony/console": "v4.4.4",
"symfony/debug": "v4.4.4",
"symfony/dependency-injection": "v4.4.4",
......
......@@ -70,7 +70,6 @@ class Config {
'squizlabs/php_codesniffer' => ['tests'],
'stack/builder' => ['tests'],
'symfony/browser-kit' => ['Tests'],
'symfony/class-loader' => ['Tests'],
'symfony/console' => ['Tests'],
'symfony/css-selector' => ['Tests'],
'symfony/debug' => ['Tests'],
......
......@@ -424,35 +424,13 @@
/**
* Class Loader.
*
* If the APC extension is detected, the Symfony APC class loader is used for
* performance reasons. Detection can be prevented by setting
* class_loader_auto_detect to false, as in the example below.
* If the APCu extension is detected, the classloader will be optimised to use
* it. Set to FALSE to disable this.
*
* @see https://getcomposer.org/doc/articles/autoloader-optimization.md
*/
# $settings['class_loader_auto_detect'] = FALSE;
/*
* If the APC extension is not detected, either because APC is missing or
* because auto-detection has been disabled, auto-loading falls back to
* Composer's ClassLoader, which is good for development as it does not break
* when code is moved in the file system. You can also decorate the base class
* loader with another cached solution than the Symfony APC class loader, as
* all production sites should have a cached class loader of some sort enabled.
*
* To do so, you may decorate and replace the local $class_loader variable. For
* example, to use Symfony's APC class loader without automatic detection,
* uncomment the code below.
*/
/*
if ($settings['hash_salt']) {
$prefix = 'drupal.' . hash('sha256', 'drupal.' . $settings['hash_salt']);
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $class_loader);
unset($prefix);
$class_loader->unregister();
$apc_loader->register();
$class_loader = $apc_loader;
}
*/
/**
* Authorized file system operations:
*
......
......@@ -18,7 +18,6 @@
"ext-tokenizer": "*",
"ext-xml": "*",
"php": ">=7.3",
"symfony/class-loader": "~3.4.0",
"symfony/console": "^4.4",
"symfony/dependency-injection": "^4.4",
"symfony/event-dispatcher": "^4.4",
......@@ -176,11 +175,29 @@
},
"classmap": [
"lib/Drupal.php",
"lib/Drupal/Component/DependencyInjection/Container.php",
"lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php",
"lib/Drupal/Component/FileCache/FileCacheFactory.php",
"lib/Drupal/Component/Utility/Timer.php",
"lib/Drupal/Component/Utility/Unicode.php",
"lib/Drupal/Core/Cache/Cache.php",
"lib/Drupal/Core/Cache/CacheBackendInterface.php",
"lib/Drupal/Core/Cache/CacheTagsChecksumInterface.php",
"lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php",
"lib/Drupal/Core/Cache/CacheTagsInvalidatorInterface.php",
"lib/Drupal/Core/Cache/DatabaseBackend.php",
"lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php",
"lib/Drupal/Core/Database/Connection.php",
"lib/Drupal/Core/Database/Database.php",
"lib/Drupal/Core/Database/Driver/mysql/Connection.php",
"lib/Drupal/Core/Database/Driver/pgsql/Connection.php",
"lib/Drupal/Core/Database/Driver/sqlite/Connection.php",
"lib/Drupal/Core/Database/Statement.php",
"lib/Drupal/Core/Database/StatementInterface.php",
"lib/Drupal/Core/DependencyInjection/Container.php",
"lib/Drupal/Core/DrupalKernel.php",
"lib/Drupal/Core/DrupalKernelInterface.php",
"lib/Drupal/Core/Installer/InstallerRedirectTrait.php",
"lib/Drupal/Core/Site/Settings.php"
]
},
......
......@@ -68,7 +68,6 @@ class Composer {
'squizlabs/php_codesniffer' => ['tests'],
'stack/builder' => ['tests'],
'symfony/browser-kit' => ['Tests'],
'symfony/class-loader' => ['Tests'],
'symfony/console' => ['Tests'],
'symfony/css-selector' => ['Tests'],
'symfony/debug' => ['Tests'],
......@@ -116,14 +115,18 @@ public static function preAutoloadDump(Event $event) {
if (!isset($autoload['classmap'])) {
$autoload['classmap'] = [];
}
// Check for our packages, and then optimize them if they're present.
// Check for packages used prior to the default classloader being able to
// use APCu and optimize them if they're present.
// @see \Drupal\Core\DrupalKernel::boot()
if ($repository->findPackage('symfony/http-foundation', $constraint)) {
$autoload['classmap'] = array_merge($autoload['classmap'], [
$vendor_dir . '/symfony/http-foundation/Request.php',
$vendor_dir . '/symfony/http-foundation/RequestStack.php',
$vendor_dir . '/symfony/http-foundation/ParameterBag.php',
$vendor_dir . '/symfony/http-foundation/FileBag.php',
$vendor_dir . '/symfony/http-foundation/ServerBag.php',
$vendor_dir . '/symfony/http-foundation/HeaderBag.php',
$vendor_dir . '/symfony/http-foundation/HeaderUtils.php',
]);
}
if ($repository->findPackage('symfony/http-kernel', $constraint)) {
......@@ -133,6 +136,30 @@ public static function preAutoloadDump(Event $event) {
$vendor_dir . '/symfony/http-kernel/TerminableInterface.php',
]);
}
if ($repository->findPackage('symfony/http-kernel', $constraint)) {
$autoload['classmap'] = array_merge($autoload['classmap'], [
$vendor_dir . '/symfony/http-kernel/HttpKernel.php',
$vendor_dir . '/symfony/http-kernel/HttpKernelInterface.php',
$vendor_dir . '/symfony/http-kernel/TerminableInterface.php',
]);
}
if ($repository->findPackage('symfony/dependency-injection', $constraint)) {
$autoload['classmap'] = array_merge($autoload['classmap'], [
$vendor_dir . '/symfony/dependency-injection/ContainerAwareInterface.php',
$vendor_dir . '/symfony/dependency-injection/ContainerInterface.php',
]);
}
if ($repository->findPackage('psr/container', $constraint)) {
$autoload['classmap'] = array_merge($autoload['classmap'], [
$vendor_dir . '/psr/container/src/ContainerInterface.php',
]);
}
if ($repository->findPackage('laminas/laminas-zendframework-bridge', $constraint)) {
$autoload['classmap'] = array_merge($autoload['classmap'], [
$vendor_dir . '/laminas/laminas-zendframework-bridge/src/Autoloader.php',
$vendor_dir . '/laminas/laminas-zendframework-bridge/src/RewriteRules.php',
]);
}
$package->setAutoload($autoload);
}
......
......@@ -24,9 +24,6 @@
use Drupal\Core\Security\RequestSanitizer;
use Drupal\Core\Site\Settings;
use Drupal\Core\Test\TestDatabase;
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\ClassLoader\WinCacheClassLoader;
use Symfony\Component\ClassLoader\XcacheClassLoader;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\RedirectResponse;
......@@ -251,8 +248,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* 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.
* front controller, but may also be decorated.
* @param string $environment
* String indicating the environment, e.g. 'prod' or 'dev'.
* @param bool $allow_dumping
......@@ -281,8 +277,7 @@ public static function createFromRequest(Request $request, $class_loader, $envir
* String indicating the environment, e.g. 'prod' or 'dev'.
* @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.
* the front controller, but may also be decorated.
* @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
......@@ -474,6 +469,15 @@ public function boot() {
// Initialize the container.
$this->initializeContainer();
// Add the APCu prefix to use to cache found/not-found classes.
if (Settings::get('class_loader_auto_detect', TRUE) && method_exists($this->classLoader, 'setApcuPrefix')) {
// Vary the APCu key by which modules are installed to allow
// class_exists() checks to determine functionality.
$id = 'class_loader:' . crc32(implode(array_keys($this->container->getParameter('container.modules')), ':'));
$prefix = Settings::getApcuPrefix($id, $this->root);
$this->classLoader->setApcuPrefix($prefix);
}
if (in_array('phar', stream_get_wrappers(), TRUE)) {
// Set up a stream wrapper to handle insecurities due to PHP's builtin
// phar stream wrapper. This is not registered as a regular stream wrapper
......@@ -1029,7 +1033,6 @@ public static function bootEnvironment($app_root = NULL) {
protected function initializeSettings(Request $request) {
$site_path = static::findSitePath($request);
$this->setSitePath($site_path);
$class_loader_class = get_class($this->classLoader);
Settings::initialize($this->root, $site_path, $this->classLoader);
// Initialize our list of trusted HTTP Host headers to protect against
......@@ -1040,40 +1043,6 @@ protected function initializeSettings(Request $request) {
throw new BadRequestHttpException('The provided host name is not valid for this server.');
}
}
// If the class loader is still the same, possibly
// upgrade to an optimized class loader.
if ($class_loader_class == get_class($this->classLoader)
&& Settings::get('class_loader_auto_detect', TRUE)) {
$prefix = Settings::getApcuPrefix('class_loader', $this->root);
$loader = NULL;
// We autodetect one of the following three optimized classloaders, if
// their underlying extension exists.
if (function_exists('apcu_fetch')) {
$loader = new ApcClassLoader($prefix, $this->classLoader);
}
elseif (extension_loaded('wincache')) {
$loader = new WinCacheClassLoader($prefix, $this->classLoader);
}
elseif (extension_loaded('xcache')) {
$loader = new XcacheClassLoader($prefix, $this->classLoader);
}
if (!empty($loader)) {
$this->classLoader->unregister();
// The optimized classloader might be persistent and store cache misses.
// For example, once a cache miss is stored in APCu clearing it on a
// specific web-head will not clear any other web-heads. Therefore
// fallback to the composer class loader that only statically caches
// misses.
$old_loader = $this->classLoader;
$this->classLoader = $loader;
// Our class loaders are prepended to ensure they come first like the
// class loader they are replacing.
$old_loader->register(TRUE);
$loader->register(TRUE);
}
}
}
/**
......
......@@ -107,7 +107,7 @@ public static function getAll() {
* @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.
* decorated.
*
* @see default.settings.php
*/
......
......@@ -4,3 +4,5 @@ name: 'ABC Help Test'
type: module
description: 'Support module for help testing.'
package: Testing
dependencies:
- help_topics
......@@ -241,6 +241,7 @@ public function testHelpSearch() {
* Tests uninstalling the help_topics module.
*/
public function testUninstall() {
\Drupal::service('module_installer')->uninstall(['help_topics_test']);
// Ensure we can uninstall help_topics and use the help system without
// breaking.
$this->drupalLogin($this->rootUser);
......
......@@ -2,14 +2,18 @@
namespace Drupal\KernelTests\Core\DrupalKernel;
use Composer\Autoload\ClassLoader;
use Drupal\Core\DrupalKernel;
use Drupal\KernelTests\KernelTestBase;
use org\bovigo\vfs\vfsStream;
use Prophecy\Argument;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests DIC compilation to disk.
*
* @group DrupalKernel
* @coversDefaultClass \Drupal\Core\DrupalKernel
*/
class DrupalKernelTest extends KernelTestBase {
......@@ -189,4 +193,64 @@ public function testPreventChangeOfSitePath() {
$kernel->setSitePath($path);
}
/**
* Data provider for self::testClassLoaderAutoDetect
* @return array
*/
public function providerClassLoaderAutoDetect() {
return [
'TRUE' => [TRUE],
'FALSE' => [FALSE],
];
}
/**
* Tests class_loader_auto_detect setting.
*
* This test runs in a separate process since it registers class loaders and
* results in statics being set.
*
* @runInSeparateProcess
* @preserveGlobalState disabled
* @covers ::boot
* @dataProvider providerClassLoaderAutoDetect
*
* @param bool $value
* The value to set class_loader_auto_detect to.
*/
public function testClassLoaderAutoDetect($value) {
// Create a virtual file system containing items that should be
// excluded. Exception being modules directory.
vfsStream::setup('root', NULL, [
'sites' => [
'default' => [],
],
'core' => [
'lib' => [
'Drupal' => [
'Core' => [],
'Component' => [],
],
],
],
]);
$this->setSetting('class_loader_auto_detect', $value);
$classloader = $this->prophesize(ClassLoader::class);
// Assert that we call the setApcuPrefix on the classloader if
// class_loader_auto_detect is set to TRUE;
if ($value) {
$classloader->setApcuPrefix(Argument::type('string'))->shouldBeCalled();
}
else {
$classloader->setApcuPrefix(Argument::type('string'))->shouldNotBeCalled();
}
// Create a kernel suitable for testing.
$kernel = new DrupalKernel('test', $classloader->reveal(), FALSE, vfsStream::url('root'));
$kernel->setSitePath(vfsStream::url('root/sites/default'));
$kernel->boot();
}
}
......@@ -5,7 +5,6 @@
use Drupal\Core\DrupalKernel;
use Drupal\Tests\UnitTestCase;
use org\bovigo\vfs\vfsStream;
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\HttpFoundation\Request;
/**
......@@ -48,63 +47,6 @@ public function testTrustedHosts($host, $server_name, $message, $expected = FALS
Request::setFactory(NULL);
}
/**
* Tests the reregistration of autoloaders if APCu available.
*
* This test runs in a separate process since it registers class loaders and
* results in statics being set.
*
* @runInSeparateProcess
* @preserveGlobalState disabled
* @requires function apcu_fetch
* @covers ::initializeSettings
*/
public function testInitializeSettings() {
$request = new Request();
$classloader = new fakeAutoloader();
// Create a kernel suitable for testing.
$kernel = $this->getMockBuilder(DrupalKernel::class)
->disableOriginalConstructor()
->setMethods(['do_not_mock_any_methods'])
->getMock();
$classloader_property = new \ReflectionProperty($kernel, 'classLoader');
$classloader_property->setAccessible(TRUE);
$classloader_property->setValue($kernel, $classloader);
$method = new \ReflectionMethod($kernel, 'initializeSettings');
$method->setAccessible(TRUE);
// Prepend another autoloader to simulate Drush's autoloader.
$fake_drush_autoloader = function () {
return NULL;
};
spl_autoload_register($fake_drush_autoloader, TRUE, TRUE);
// Before calling DrupalKernel::initializeSettings() the first autoloader
// is the fake Drush autoloader.
$this->assertSame($fake_drush_autoloader, spl_autoload_functions()[0]);
// Call DrupalKernel::initializeSettings() to simulate part of a Drupal
// bootstrap. During the include of autoload.php Composer would prepend
// Drupal's autoloader and then this method should not result in Drush's
// autoloader becoming the first autoloader even if it swaps out
// Composer's autoloader for an optimised one.
$method->invoke($kernel, $request);
$autoloaders = spl_autoload_functions();
// The first autoloader should be the APCu based autoloader.
$this->assertInstanceOf(ApcClassLoader::class, $autoloaders[0][0]);
// The second autoloader should be the original autoloader the kernel was
// constructed with.
$this->assertSame($classloader, $autoloaders[1][0]);
// The third autoloader should be Drush's autoloader.
$this->assertSame($fake_drush_autoloader, $autoloaders[2]);
// Reset the request factory because it is statically stored on the
// request.
Request::setFactory(NULL);
}
/**
* Provides test data for testTrustedHosts().
*/
......
......@@ -140,11 +140,6 @@ public static function isDeprecationSkipped($message) {
*/
public static function getSkippedDeprecations() {
return [
'The Symfony\Component\ClassLoader\ApcClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.',
// The following deprecation is not triggered by DrupalCI testing since it
// is a Windows only deprecation. Remove when core no longer uses
// WinCacheClassLoader in \Drupal\Core\DrupalKernel::initializeSettings().
'The Symfony\Component\ClassLoader\WinCacheClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.',
// The following deprecation message is skipped for testing purposes.
'\Drupal\Tests\SkippedDeprecationTest deprecation',
// These deprecations are triggered by symfony/psr-http-message-factory
......
......@@ -424,35 +424,13 @@
/**
* Class Loader.
*
* If the APC extension is detected, the Symfony APC class loader is used for
* performance reasons. Detection can be prevented by setting
* class_loader_auto_detect to false, as in the example below.
* If the APCu extension is detected, the classloader will be optimised to use
* it. Set to FALSE to disable this.
*
* @see https://getcomposer.org/doc/articles/autoloader-optimization.md
*/
# $settings['class_loader_auto_detect'] = FALSE;
/*
* If the APC extension is not detected, either because APC is missing or
* because auto-detection has been disabled, auto-loading falls back to
* Composer's ClassLoader, which is good for development as it does not break
* when code is moved in the file system. You can also decorate the base class
* loader with another cached solution than the Symfony APC class loader, as
* all production sites should have a cached class loader of some sort enabled.
*
* To do so, you may decorate and replace the local $class_loader variable. For
* example, to use Symfony's APC class loader without automatic detection,
* uncomment the code below.
*/
/*
if ($settings['hash_salt']) {
$prefix = 'drupal.' . hash('sha256', 'drupal.' . $settings['hash_salt']);
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $class_loader);
unset($prefix);
$class_loader->unregister();
$apc_loader->register();
$class_loader = $apc_loader;
}
*/
/**
* Authorized file system operations:
*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment