summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorNathaniel Catchpole2014-06-05 10:30:04 (GMT)
committerNathaniel Catchpole2014-06-05 10:30:04 (GMT)
commitcda051c425ec10e864d3207cc0e60640bfa16e10 (patch)
tree7a273719f52a92c9be0d9f21b5bb7ce47eae84d5 /core
parent2cd0b096b925f0b3693df45c9681acc546c92bc9 (diff)
Issue #2016629 by larowlan, neclimdul, sun, alexpott, jibran, ParisLiakos, donquixote, effulgentsia, msonnabaum: Refactor bootstrap to better utilize the kernel.
Diffstat (limited to 'core')
-rw-r--r--core/authorize.php19
-rw-r--r--core/core.services.yml8
-rw-r--r--core/includes/bootstrap.inc569
-rw-r--r--core/includes/common.inc64
-rw-r--r--core/includes/errors.inc8
-rw-r--r--core/includes/install.core.inc23
-rw-r--r--core/includes/install.inc29
-rw-r--r--core/includes/path.inc4
-rw-r--r--core/includes/schema.inc2
-rw-r--r--core/includes/theme.inc10
-rw-r--r--core/includes/utility.inc26
-rw-r--r--core/lib/Drupal/Core/DrupalKernel.php556
-rw-r--r--core/lib/Drupal/Core/DrupalKernelInterface.php43
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php64
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php47
-rw-r--r--core/lib/Drupal/Core/Site/Settings.php27
-rw-r--r--core/lib/Drupal/Core/Test/TestKernel.php44
-rw-r--r--core/lib/Drupal/Core/Test/TestRunnerKernel.php85
-rw-r--r--core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php16
-rw-r--r--core/modules/dblog/src/Tests/DbLogTest.php4
-rw-r--r--core/modules/field/src/Tests/FieldHelpTest.php1
-rw-r--r--core/modules/simpletest/src/InstallerTestBase.php14
-rw-r--r--core/modules/simpletest/src/KernelTestBase.php32
-rw-r--r--core/modules/simpletest/src/TestBase.php3
-rw-r--r--core/modules/simpletest/src/WebTestBase.php60
-rw-r--r--core/modules/statistics/statistics.php19
-rw-r--r--core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php89
-rw-r--r--core/modules/system/src/Tests/Entity/EntityViewControllerTest.php2
-rw-r--r--core/modules/system/src/Tests/Menu/MenuRouterTest.php1
-rw-r--r--core/modules/system/src/Tests/System/ScriptTest.php8
-rw-r--r--core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php6
-rw-r--r--core/modules/system/tests/http.php26
-rw-r--r--core/modules/system/tests/https.php26
-rw-r--r--core/modules/toolbar/toolbar.module4
-rw-r--r--core/modules/user/src/Tests/UserLoginTest.php1
-rw-r--r--core/modules/views_ui/src/Tests/PreviewTest.php2
-rw-r--r--core/rebuild.php23
-rwxr-xr-xcore/scripts/password-hash.sh11
-rwxr-xr-xcore/scripts/rebuild_token_calculator.sh10
-rwxr-xr-xcore/scripts/run-tests.sh53
-rw-r--r--core/tests/bootstrap.php2
-rw-r--r--core/update.php40
42 files changed, 1115 insertions, 966 deletions
diff --git a/core/authorize.php b/core/authorize.php
index f938f39..96fe9ae 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -20,13 +20,15 @@
* @link authorize Authorized operation helper functions @endlink
*/
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Site\Settings;
use Drupal\Core\Page\DefaultHtmlPageRenderer;
// Change the directory to the Drupal root.
chdir('..');
-require_once __DIR__ . '/vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
/**
* Global flag to identify update.php and authorize.php runs.
@@ -51,18 +53,9 @@ function authorize_access_allowed() {
return Settings::get('allow_authorize_operations', TRUE) && user_access('administer software updates');
}
-// *** Real work of the script begins here. ***
-
-require_once __DIR__ . '/includes/bootstrap.inc';
-require_once __DIR__ . '/includes/common.inc';
-require_once __DIR__ . '/includes/file.inc';
-require_once __DIR__ . '/includes/module.inc';
-require_once __DIR__ . '/includes/ajax.inc';
-
-// Prepare a minimal bootstrap.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-$request = \Drupal::request();
-\Drupal::service('request_stack')->push($request);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
+$kernel->prepareLegacyRequest($request);
// We have to enable the user and system modules, even to check access and
// display errors via the maintenance theme.
diff --git a/core/core.services.yml b/core/core.services.yml
index 6a2a468..41ee373 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -197,6 +197,10 @@ services:
arguments: ['@access_check.theme', '@request_stack']
tags:
- { name: service_collector, tag: theme_negotiator, call: addNegotiator }
+ theme.negotiator.request_subscriber:
+ class: Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber
+ tags:
+ - { name: event_subscriber }
theme.negotiator.default:
class: Drupal\Core\Theme\DefaultNegotiator
arguments: ['@config.factory']
@@ -590,10 +594,6 @@ services:
tags:
- { name: event_subscriber }
arguments: ['@path.alias_manager', '@path_processor_manager']
- legacy_request_subscriber:
- class: Drupal\Core\EventSubscriber\LegacyRequestSubscriber
- tags:
- - { name: event_subscriber }
finish_response_subscriber:
class: Drupal\Core\EventSubscriber\FinishResponseSubscriber
tags:
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 3d41fcb..3e4fca8 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -6,28 +6,16 @@
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Environment;
-use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\String;
-use Drupal\Component\Utility\Timer;
use Drupal\Component\Utility\Unicode;
-use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\DrupalKernel;
-use Drupal\Core\Database\Database;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Site\Settings;
-use Drupal\Core\Utility\Title;
use Drupal\Core\Utility\Error;
use Symfony\Component\ClassLoader\ApcClassLoader;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\DependencyInjection\Container;
-use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Language\Language;
-use Drupal\Core\Lock\DatabaseLockBackend;
-use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Session\AnonymousUserSession;
/**
@@ -126,26 +114,36 @@ const WATCHDOG_DEBUG = 7;
/**
* First bootstrap phase: initialize configuration.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
const DRUPAL_BOOTSTRAP_CONFIGURATION = 0;
/**
- * Second bootstrap phase, initalize a kernel.
+ * Second bootstrap phase, initialize a kernel.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
const DRUPAL_BOOTSTRAP_KERNEL = 1;
/**
* Third bootstrap phase: try to serve a cached page.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
const DRUPAL_BOOTSTRAP_PAGE_CACHE = 2;
/**
* Fourth bootstrap phase: load code for subsystems and modules.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
const DRUPAL_BOOTSTRAP_CODE = 3;
/**
* Final bootstrap phase: initialize language, path, theme, and modules.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
const DRUPAL_BOOTSTRAP_FULL = 4;
@@ -207,11 +205,6 @@ define('DRUPAL_ROOT', dirname(dirname(__DIR__)));
/**
* Returns the appropriate configuration directory.
*
- * Returns the configuration path based on the site's hostname, port, and
- * pathname. Uses find_conf_path() to find the current configuration directory.
- * See default.settings.php for examples on how the URL is converted to a
- * directory.
- *
* @param bool $require_settings
* Only configuration directories with an existing settings.php file
* will be recognized. Defaults to TRUE. During initial installation,
@@ -220,100 +213,36 @@ define('DRUPAL_ROOT', dirname(dirname(__DIR__)));
* @param bool $reset
* Force a full search for matching directories even if one had been
* found previously. Defaults to FALSE.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * (optional) The current request. Defaults to \Drupal::request() or a new
+ * request created from globals.
*
- * @return
- * The path of the matching directory.
+ * @return string
+ * The path of the matching directory.@see default.settings.php
*
- * @see default.settings.php
- */
-function conf_path($require_settings = TRUE, $reset = FALSE) {
- static $conf_path;
-
- if (isset($conf_path) && !$reset) {
- return $conf_path;
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ * Use \Drupal\Core\DrupalKernel::getSitePath() instead. If the kernel is
+ * unavailable or the site path needs to be recalculated then
+ * Drupal\Core\DrupalKernel::findSitePath() can be used.
+ */
+function conf_path($require_settings = TRUE, $reset = FALSE, Request $request = NULL) {
+ if (!isset($request)) {
+ if (\Drupal::hasRequest()) {
+ $request = \Drupal::request();
+ }
+ // @todo Remove once external CLI scripts (Drush) are updated.
+ else {
+ $request = Request::createFromGlobals();
+ }
}
-
- // Check for a simpletest override.
- if ($test_prefix = drupal_valid_test_ua()) {
- $conf_path = 'sites/simpletest/' . substr($test_prefix, 10);
- return $conf_path;
+ if (\Drupal::hasService('kernel')) {
+ $site_path = \Drupal::service('kernel')->getSitePath();
}
-
- // Otherwise, use the normal $conf_path.
- $script_name = $_SERVER['SCRIPT_NAME'];
- if (!$script_name) {
- $script_name = $_SERVER['SCRIPT_FILENAME'];
+ if (!isset($site_path) || empty($site_path)) {
+ $site_path = DrupalKernel::findSitePath($request, $require_settings);
}
- $http_host = $_SERVER['HTTP_HOST'];
- $conf_path = find_conf_path($http_host, $script_name, $require_settings);
- return $conf_path;
+ return $site_path;
}
-
-/**
- * Finds the appropriate configuration directory for a given host and path.
- *
- * Finds a matching configuration directory file by stripping the website's
- * hostname from left to right and pathname from right to left. By default,
- * the directory must contain a 'settings.php' file for it to match. If the
- * parameter $require_settings is set to FALSE, then a directory without a
- * 'settings.php' file will match as well. The first configuration
- * file found will be used and the remaining ones will be ignored. If no
- * configuration file is found, returns a default value '$confdir/default'. See
- * default.settings.php for examples on how the URL is converted to a directory.
- *
- * If a file named sites.php is present in the $confdir, it will be loaded
- * prior to scanning for directories. That file can define aliases in an
- * associative array named $sites. The array is written in the format
- * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
- * directory alias for http://www.drupal.org:8080/mysite/test whose configuration
- * file is in sites/example.com, the array should be defined as:
- * @code
- * $sites = array(
- * '8080.www.drupal.org.mysite.test' => 'example.com',
- * );
- * @endcode
- *
- * @param $http_host
- * The hostname and optional port number, e.g. "www.example.com" or
- * "www.example.com:8080".
- * @param $script_name
- * The part of the URL following the hostname, including the leading slash.
- * @param $require_settings
- * Defaults to TRUE. If TRUE, then only match directories with a
- * 'settings.php' file. Otherwise match any directory.
- *
- * @return
- * The path of the matching configuration directory.
- *
- * @see default.settings.php
- * @see example.sites.php
- * @see conf_path()
- */
-function find_conf_path($http_host, $script_name, $require_settings = TRUE) {
- // Determine whether multi-site functionality is enabled.
- if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
- return 'sites/default';
- }
-
- $sites = array();
- include DRUPAL_ROOT . '/sites/sites.php';
-
- $uri = explode('/', $script_name);
- $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
- for ($i = count($uri) - 1; $i > 0; $i--) {
- for ($j = count($server); $j > 0; $j--) {
- $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
- if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
- $dir = $sites[$dir];
- }
- if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
- return "sites/$dir";
- }
- }
- }
- return 'sites/default';
-}
-
/**
* Returns the path of a configuration directory.
*
@@ -334,207 +263,6 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) {
}
/**
- * Initializes the PHP environment.
- */
-function drupal_environment_initialize() {
- if (!isset($_SERVER['SERVER_PROTOCOL']) || ($_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.0' && $_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.1')) {
- $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
- }
-
- if (isset($_SERVER['HTTP_HOST'])) {
- // As HTTP_HOST is user input, ensure it only contains characters allowed
- // in hostnames. See RFC 952 (and RFC 2181).
- // $_SERVER['HTTP_HOST'] is lowercased here per specifications.
- $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
- if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) {
- // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
- header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
- exit;
- }
- }
- else {
- // Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
- // defined for E_ALL compliance.
- $_SERVER['HTTP_HOST'] = '';
- }
-
- // @todo Refactor with the Symfony Request object.
- _current_path(request_path());
-
- // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
- error_reporting(E_STRICT | E_ALL | error_reporting());
-
- // Override PHP settings required for Drupal to work properly.
- // sites/default/default.settings.php contains more runtime settings.
- // The .htaccess file contains settings that cannot be changed at runtime.
-
- // Use session cookies, not transparent sessions that puts the session id in
- // the query string.
- ini_set('session.use_cookies', '1');
- ini_set('session.use_only_cookies', '1');
- ini_set('session.use_trans_sid', '0');
- // Don't send HTTP headers using PHP's session handler.
- // Send an empty string to disable the cache limiter.
- ini_set('session.cache_limiter', '');
- // Use httponly session cookies.
- ini_set('session.cookie_httponly', '1');
-
- // Set sane locale settings, to ensure consistent string, dates, times and
- // numbers handling.
- setlocale(LC_ALL, 'C');
-}
-
-/**
- * Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
- *
- * @return
- * TRUE if only containing valid characters, or FALSE otherwise.
- */
-function drupal_valid_http_host($host) {
- return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
-}
-
-/**
- * Sets the base URL, cookie domain, and session name from configuration.
- */
-function drupal_settings_initialize() {
- // Export these settings.php variables to the global namespace.
- global $base_url, $cookie_domain, $config_directories, $config;
- $databases = array();
- $settings = array();
- $config = array();
-
- // Make conf_path() available as local variable in settings.php.
- $conf_path = conf_path();
- if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
- require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
- }
- // Initialize Database.
- Database::setMultipleConnectionInfo($databases);
- // Initialize Settings.
- new Settings($settings);
-}
-
-/**
- * Initializes global request variables.
- *
- * @todo D8: Eliminate this entirely in favor of Request object.
- */
-function _drupal_request_initialize() {
- // Provided by settings.php.
- // @see drupal_settings_initialize()
- global $base_url, $cookie_domain;
- // Set and derived from $base_url by this function.
- global $base_path, $base_root, $script_path;
- global $base_secure_url, $base_insecure_url;
-
- $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
-
- if (isset($base_url)) {
- // Parse fixed base URL from settings.php.
- $parts = parse_url($base_url);
- if (!isset($parts['path'])) {
- $parts['path'] = '';
- }
- $base_path = $parts['path'] . '/';
- // Build $base_root (everything until first slash after "scheme://").
- $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
- }
- else {
- // Create base URL
- $http_protocol = $is_https ? 'https' : 'http';
- $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
-
- $base_url = $base_root;
-
- // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
- // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
- if ($dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')) {
- // Remove "core" directory if present, allowing install.php, update.php,
- // and others to auto-detect a base path.
- $core_position = strrpos($dir, '/core');
- if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
- $base_path = substr($dir, 0, $core_position);
- }
- else {
- $base_path = $dir;
- }
- $base_url .= $base_path;
- $base_path .= '/';
- }
- else {
- $base_path = '/';
- }
- }
- $base_secure_url = str_replace('http://', 'https://', $base_url);
- $base_insecure_url = str_replace('https://', 'http://', $base_url);
-
- // Determine the path of the script relative to the base path, and add a
- // trailing slash. This is needed for creating URLs to Drupal pages.
- if (!isset($script_path)) {
- $script_path = '';
- // We don't expect scripts outside of the base path, but sanity check
- // anyway.
- if (strpos($_SERVER['SCRIPT_NAME'], $base_path) === 0) {
- $script_path = substr($_SERVER['SCRIPT_NAME'], strlen($base_path)) . '/';
- // If the request URI does not contain the script name, then clean URLs
- // are in effect and the script path can be similarly dropped from URL
- // generation. For servers that don't provide $_SERVER['REQUEST_URI'], we
- // do not know the actual URI requested by the client, and request_uri()
- // returns a URI with the script name, resulting in non-clean URLs unless
- // there's other code that intervenes.
- if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
- $script_path = '';
- }
- // @todo Temporary BC for install.php, update.php, and other scripts.
- // - http://drupal.org/node/1547184
- // - http://drupal.org/node/1546082
- if ($script_path !== 'index.php/') {
- $script_path = '';
- }
- }
- }
-
- if ($cookie_domain) {
- // If the user specifies the cookie domain, also use it for session name.
- $session_name = $cookie_domain;
- }
- else {
- // Otherwise use $base_url as session name, without the protocol
- // to use the same session identifiers across HTTP and HTTPS.
- list( , $session_name) = explode('://', $base_url, 2);
- // HTTP_HOST can be modified by a visitor, but we already sanitized it
- // in drupal_settings_initialize().
- if (!empty($_SERVER['HTTP_HOST'])) {
- $cookie_domain = $_SERVER['HTTP_HOST'];
- // Strip leading periods, www., and port numbers from cookie domain.
- $cookie_domain = ltrim($cookie_domain, '.');
- if (strpos($cookie_domain, 'www.') === 0) {
- $cookie_domain = substr($cookie_domain, 4);
- }
- $cookie_domain = explode(':', $cookie_domain);
- $cookie_domain = '.' . $cookie_domain[0];
- }
- }
- // Per RFC 2109, cookie domains must contain at least one dot other than the
- // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
- if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
- ini_set('session.cookie_domain', $cookie_domain);
- }
- // To prevent session cookies from being hijacked, a user can configure the
- // SSL version of their website to only transfer session cookies via SSL by
- // using PHP's session.cookie_secure setting. The browser will then use two
- // separate session cookies for the HTTPS and HTTP versions of the site. So we
- // must use different session identifiers for HTTPS and HTTP to prevent a
- // cookie collision.
- if ($is_https) {
- ini_set('session.cookie_secure', TRUE);
- }
- $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
- session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
-}
-
-/**
* Returns and optionally sets the filename for a system resource.
*
* The filename, whether provided, cached, or retrieved from the database, is
@@ -1256,138 +984,54 @@ function drupal_anonymous_user() {
}
/**
- * Ensures Drupal is bootstrapped to the specified phase.
- *
- * In order to bootstrap Drupal from another PHP script, you can use this code:
- * @code
- * require_once '/path/to/drupal/core/vendor/autoload.php';
- * require_once '/path/to/drupal/core/includes/bootstrap.inc';
- * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
- * @endcode
+ * Bootstraps DrupalKernel to a given boot level.
*
* @param $phase
- * A constant telling which phase to bootstrap to. When you bootstrap to a
- * particular phase, all earlier phases are run automatically. Possible
- * values:
+ * A constant telling which phase to bootstrap to. Possible values:
* - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
* - DRUPAL_BOOTSTRAP_KERNEL: Initalizes a kernel.
- * - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
- * - DRUPAL_BOOTSTRAP_CODE: Loads code for subsystems and modules.
- * - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
- * data.
*
- * @return
+ * @return int
* The most recently completed phase.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ * Interact directly with the kernel.
+ *
+ * @todo Obsolete. Remove once Drush has been updated.
*/
function drupal_bootstrap($phase = NULL) {
- // Not drupal_static(), because does not depend on any run-time information.
- static $phases = array(
- DRUPAL_BOOTSTRAP_CONFIGURATION,
- DRUPAL_BOOTSTRAP_KERNEL,
- DRUPAL_BOOTSTRAP_PAGE_CACHE,
- DRUPAL_BOOTSTRAP_CODE,
- DRUPAL_BOOTSTRAP_FULL,
- );
- // Not drupal_static(), because the only legitimate API to control this is to
- // call drupal_bootstrap() with a new phase parameter.
- static $final_phase = -1;
- // Not drupal_static(), because it's impossible to roll back to an earlier
- // bootstrap state.
- static $stored_phase = -1;
-
- // Store the phase name so it's not forgotten during recursion. Additionally,
- // ensure that $final_phase is never rolled back to an earlier bootstrap
- // state.
- if ($phase > $final_phase) {
- $final_phase = $phase;
- }
+ // Temporary variables used for booting later legacy phases.
+ /** @var \Drupal\Core\DrupalKernel $kernel */
+ static $kernel;
+ static $boot_level = 0;
+
if (isset($phase)) {
- // Call a phase if it has not been called before and is below the requested
- // phase.
- while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
- $current_phase = array_shift($phases);
-
- // This function is re-entrant. Only update the completed phase when the
- // current call actually resulted in a progress in the bootstrap process.
- if ($current_phase > $stored_phase) {
- $stored_phase = $current_phase;
- }
+ $request = Request::createFromGlobals();
+ for ($current_phase = $boot_level; $current_phase <= $phase; $current_phase++) {
switch ($current_phase) {
case DRUPAL_BOOTSTRAP_CONFIGURATION:
- _drupal_bootstrap_configuration();
+ $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod');
break;
case DRUPAL_BOOTSTRAP_KERNEL:
- _drupal_bootstrap_kernel();
+ $kernel->boot();
break;
case DRUPAL_BOOTSTRAP_PAGE_CACHE:
- _drupal_bootstrap_page_cache();
+ $kernel->handlePageCache($request);
break;
case DRUPAL_BOOTSTRAP_CODE:
- require_once __DIR__ . '/common.inc';
- _drupal_bootstrap_code();
- break;
-
case DRUPAL_BOOTSTRAP_FULL:
- _drupal_bootstrap_full();
+ $kernel->prepareLegacyRequest($request);
break;
}
}
+ $boot_level = $phase;
}
- return $stored_phase;
-}
-
-/**
- * Handles an entire PHP request.
- *
- * This function may be called by PHP scripts (e.g., Drupal's index.php) that
- * want Drupal to take over the entire PHP processing of the request. The only
- * expectation is that PHP's superglobals are initialized as desired (PHP does
- * this automatically, but some scripts might want to alter them) and that the
- * DRUPAL_ROOT constant is defined and set to the absolute server directory of
- * Drupal's codebase.
- *
- * Scripts and applications that want to invoke multiple Drupal requests within
- * a single PHP request, or Drupal request handling within some larger workflow,
- * should not call this function, but instead instantiate and use
- * \Drupal\Core\DrupalKernel as needed.
- *
- * @param boolean $test_only
- * Whether to restrict handling to only requests invoked by SimpleTest.
- *
- * @see index.php
- */
-function drupal_handle_request($test_only = FALSE) {
- // Initialize the environment, load settings.php, and activate a PSR-0 class
- // autoloader with required namespaces registered.
- drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
- // Exit if we should be in a test environment but aren't.
- if ($test_only && !drupal_valid_test_ua()) {
- header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
- exit;
- }
-
- $kernel = new DrupalKernel('prod', drupal_classloader(), !$test_only);
- // @todo Remove this once everything in the bootstrap has been
- // converted to services in the DIC.
- $kernel->boot();
-
- // Create a request object from the HttpFoundation.
- $request = Request::createFromGlobals();
- $container = \Drupal::getContainer();
- $container->set('request', $request);
- $container->get('request_stack')->push($request);
-
- drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
-
- $response = $kernel->handle($request)->prepare($request)->send();
-
- $kernel->terminate($request, $response);
+ return \Drupal::getContainer() ? DRUPAL_BOOTSTRAP_CODE : DRUPAL_BOOTSTRAP_CONFIGURATION;
}
/**
@@ -1470,110 +1114,13 @@ function _drupal_exception_handler($exception) {
}
/**
- * Sets up the script environment and loads settings.php.
- */
-function _drupal_bootstrap_configuration() {
- drupal_environment_initialize();
-
- // Indicate that code is operating in a test child site.
- if ($test_prefix = drupal_valid_test_ua()) {
- // Only code that interfaces directly with tests should rely on this
- // constant; e.g., the error/exception handler conditionally adds further
- // error information into HTTP response headers that are consumed by
- // Simpletest's internal browser.
- define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
-
- // Log fatal errors to the test site directory.
- ini_set('log_errors', 1);
- ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
- }
- else {
- // Ensure that no other code defines this.
- define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
- }
-
- // Initialize the configuration, including variables from settings.php.
- drupal_settings_initialize();
- _drupal_request_initialize();
-
- // Activate the class loader.
- drupal_classloader();
-
- // Start a page timer:
- Timer::start('page');
-
- // Detect string handling method.
- Unicode::check();
-
- // Set the Drupal custom error handler. (requires \Drupal::config())
- set_error_handler('_drupal_error_handler');
- set_exception_handler('_drupal_exception_handler');
-
- // 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
- // settings.php file) and we are not already installing.
- if (!Database::getConnectionInfo() && !drupal_installation_attempted() && !drupal_is_cli()) {
- include_once __DIR__ . '/install.inc';
- install_goto('core/install.php');
- }
-}
-
-/**
- * Initialize the kernel / service container.
- */
-function _drupal_bootstrap_kernel() {
- // Normally, index.php puts a container in the Drupal class by creating a
- // kernel. If there is no container yet, create one.
- if (!\Drupal::getContainer()) {
- $kernel = new DrupalKernel('prod', drupal_classloader());
- $kernel->boot();
- $request = Request::createFromGlobals();
- $container = \Drupal::getContainer();
- $container->set('request', $request);
- $container->get('request_stack')->push($request);
- }
-}
-
-/**
- * Attempts to serve a page from the cache.
- */
-function _drupal_bootstrap_page_cache() {
- require_once __DIR__ . '/database.inc';
- // Check for a cache mode force from settings.php.
- if (Settings::get('page_cache_without_database')) {
- $cache_enabled = TRUE;
- }
- else {
- $config = \Drupal::config('system.performance');
- $cache_enabled = $config->get('cache.page.use_internal');
- }
-
- $request = \Drupal::request();
- // If there is no session cookie and cache is enabled (or forced), try
- // to serve a cached page.
- if (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) {
- // Get the page from the cache.
- $response = drupal_page_get_cache($request);
- // If there is a cached page, display it.
- if ($response) {
- $response->headers->set('X-Drupal-Cache', 'HIT');
-
- drupal_serve_page_from_cache($response, $request);
-
- // We are done.
- $response->prepare($request);
- $response->send();
- exit;
- }
- }
-}
-
-/**
* Returns the current bootstrap phase for this Drupal process.
*
* The current phase is the one most recently completed by drupal_bootstrap().
*
* @see drupal_bootstrap()
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
*/
function drupal_get_bootstrap_phase() {
return drupal_bootstrap();
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5572e54..62c8ed7 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2604,70 +2604,6 @@ function drupal_valid_token($token, $value = '') {
}
/**
- * Loads code for subsystems and modules, and registers stream wrappers.
- */
-function _drupal_bootstrap_code() {
- require_once __DIR__ . '/../../' . Settings::get('path_inc', 'core/includes/path.inc');
- require_once __DIR__ . '/module.inc';
- require_once __DIR__ . '/theme.inc';
- require_once __DIR__ . '/pager.inc';
- require_once __DIR__ . '/../../' . Settings::get('menu_inc', 'core/includes/menu.inc');
- require_once __DIR__ . '/tablesort.inc';
- require_once __DIR__ . '/file.inc';
- require_once __DIR__ . '/unicode.inc';
- require_once __DIR__ . '/form.inc';
- require_once __DIR__ . '/mail.inc';
- require_once __DIR__ . '/ajax.inc';
- require_once __DIR__ . '/errors.inc';
- require_once __DIR__ . '/schema.inc';
- require_once __DIR__ . '/entity.inc';
-
- // Load all enabled modules
- \Drupal::moduleHandler()->loadAll();
-
- // Make sure all stream wrappers are registered.
- file_get_stream_wrappers();
- // Ensure mt_rand() is reseeded to prevent random values from one page load
- // being exploited to predict random values in subsequent page loads.
- $seed = unpack("L", Crypt::randomBytes(4));
- mt_srand($seed[1]);
-
- // Set the allowed protocols once we have the config available.
- $allowed_protocols = \Drupal::config('system.filter')->get('protocols');
- if (!isset($allowed_protocols)) {
- // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by the
- // installer and update.php, in which case the configuration may not exist
- // (yet). Provide a minimal default set of allowed protocols for these
- // cases.
- $allowed_protocols = array('http', 'https');
- }
- UrlHelper::setAllowedProtocols($allowed_protocols);
-}
-
-/**
- * Temporary BC function for scripts not using DrupalKernel.
- *
- * DrupalKernel skips this and replicates it via event listeners.
- *
- * @see \Drupal\Core\EventSubscriber\PathSubscriber;
- * @see \Drupal\Core\EventSubscriber\LegacyRequestSubscriber;
- */
-function _drupal_bootstrap_full($skip = FALSE) {
- static $called = FALSE;
-
- if ($called || $skip) {
- $called = TRUE;
- return;
- }
-
- // Let all modules take action before the menu system handles the request.
- // We do not want this while running update.php.
- if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
- drupal_theme_initialize();
- }
-}
-
-/**
* Stores the current page in the cache.
*
* If page_compression is enabled, a gzipped version of the page is stored in
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 8b0b9e4..ebe1cd5 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -120,7 +120,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
$is_installer = drupal_installation_attempted();
// Initialize a maintenance theme if the bootstrap was not complete.
// Do it early because drupal_set_message() triggers a drupal_theme_initialize().
- if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
+ if ($fatal && drupal_get_bootstrap_phase() < DRUPAL_BOOTSTRAP_CODE) {
// The installer initializes a maintenance theme at the earliest possible
// point in time already. Do not unset that.
if (!$is_installer) {
@@ -244,9 +244,9 @@ function _drupal_log_error($error, $fatal = FALSE) {
/**
* Returns the current error level.
*
- * This function should only be used to get the current error level pre
- * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other
- * situations the following code is preferred:
+ * This function should only be used to get the current error level prior to
+ * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other situations
+ * the following code is preferred:
* @code
* \Drupal::config('system.logging')->get('error_level');
* @endcode
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index b00d23b..ed2fc97 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -272,12 +272,6 @@ function install_begin_request(&$install_state) {
// Allow command line scripts to override server variables used by Drupal.
require_once __DIR__ . '/bootstrap.inc';
- // Initialize conf_path().
- // This primes the site path to be used during installation. By not requiring
- // settings.php, a bare site folder can be prepared in the /sites directory,
- // which will be used for installing Drupal.
- conf_path(FALSE);
-
// If the hash salt leaks, it becomes possible to forge a valid testing user
// agent, install a new copy of Drupal, and take over the original site.
// The user agent header is used to pass a database prefix in the request when
@@ -288,7 +282,8 @@ function install_begin_request(&$install_state) {
exit;
}
- drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+ $site_path = DrupalKernel::findSitePath($request, FALSE);
+ Settings::initialize($site_path);
// Ensure that procedural dependencies are loaded as early as possible,
// since the error/exception handlers depend on them.
@@ -356,27 +351,24 @@ function install_begin_request(&$install_state) {
$environment = 'prod';
}
- $kernel = new DrupalKernel($environment, drupal_classloader(), FALSE);
+ $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), $environment, FALSE);
+ $kernel->setSitePath($site_path);
$kernel->boot();
-
- // Enter the request scope and add the Request.
- // @todo Remove this after converting all installer screens into controllers.
$container = $kernel->getContainer();
- $container->enterScope('request');
- $container->set('request', $request, 'request');
- $container->get('request_stack')->push($request);
// Register the file translation service.
if (isset($GLOBALS['config']['locale.settings']['translation.path'])) {
$directory = $GLOBALS['config']['locale.settings']['translation.path'];
}
else {
- $directory = conf_path() . '/files/translations';
+ $directory = $site_path . '/files/translations';
}
$container->set('string_translator.file_translation', new FileTranslation($directory));
$container->get('string_translation')
->addTranslator($container->get('string_translator.file_translation'));
+ $kernel->prepareLegacyRequest($request);
+
// Set the default language to the selected language, if any.
if (isset($install_state['parameters']['langcode'])) {
$default_language = new Language(array('id' => $install_state['parameters']['langcode']));
@@ -1455,7 +1447,6 @@ function install_load_profile(&$install_state) {
* An array of information about the current installation state.
*/
function install_bootstrap_full() {
- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
\Drupal::service('session_manager')->initialize();
}
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 67e41f6..ce7db87 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -9,8 +9,6 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\OpCodeCache;
use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\Database\Database;
-use Drupal\Core\DrupalKernel;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Site\Settings;
@@ -634,24 +632,29 @@ function drupal_verify_profile($install_state) {
* to set the default language.
*/
function drupal_install_system($install_state) {
- // Boot a new kernel into a regular production environment.
- $request = \Drupal::hasRequest() ? \Drupal::request() : FALSE;
-
+ // Remove the service provider of the early installer.
unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']);
- $kernel = new DrupalKernel('prod', drupal_classloader(), FALSE);
- $kernel->boot();
- if ($request) {
- $kernel->getContainer()->enterScope('request');
- $kernel->getContainer()->set('request', $request, 'request');
- $kernel->getContainer()->get('request_stack')->push($request);
- }
+ // Reboot into a full production environment to continue the installation.
+ $kernel = \Drupal::service('kernel');
+ $kernel->shutdown();
+ $kernel->prepareLegacyRequest(\Drupal::request());
// Install base system configuration.
\Drupal::service('config.installer')->installDefaultConfig('core', 'core');
// Install System module.
- \Drupal::moduleHandler()->install(array('system'), FALSE);
+ $kernel->getContainer()->get('module_handler')->install(array('system'), FALSE);
+
+ // DrupalKernel::prepareLegacyRequest() above calls into
+ // DrupalKernel::bootCode(), which primes file_get_stream_wrappers()'s static
+ // list of custom stream wrappers that are based on the currently enabled
+ // list of modules (none).
+ // @todo Custom stream wrappers of a new module have to be registered as soon
+ // as the module is installed/enabled. Fix either ModuleHandler::install()
+ // and/or DrupalKernel::updateModules().
+ // @see https://drupal.org/node/2028109
+ drupal_static_reset('file_get_stream_wrappers');
// Ensure default language is saved.
if (isset($install_state['parameters']['langcode'])) {
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 6043749..a10f0e7 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -74,9 +74,7 @@ function drupal_match_path($path, $patterns) {
* - http://example.com/path/alias (which is a path alias for node/306) returns
* "node/306" as opposed to the path alias.
*
- * This function is available only after DRUPAL_BOOTSTRAP_FULL.
- *
- * @return
+ * @return string
* The current Drupal URL path.
*
* @see request_path()
diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index a386e62..f181c54 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -86,7 +86,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
// If the schema is empty, avoid saving it: some database engines require
// the schema to perform queries, and this could lead to infinite loops.
- if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
+ if (!empty($schema)) {
\Drupal::cache()->set('schema', $schema, Cache::PERMANENT);
}
}
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2b06429..7e92f95 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -24,6 +24,7 @@ use Drupal\Core\Template\RenderWrapper;
use Drupal\Core\Theme\ThemeSettings;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Render\Element;
+use Symfony\Component\HttpFoundation\Request;
/**
* @defgroup content_flags Content markers
@@ -91,8 +92,11 @@ function drupal_theme_access($theme) {
/**
* Initializes the theme system by loading the theme.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The request for which to initialize the theme.
*/
-function drupal_theme_initialize() {
+function drupal_theme_initialize(Request $request = NULL) {
global $theme, $theme_key;
// If $theme is already set, assume the others are set, too, and do nothing
@@ -105,7 +109,9 @@ function drupal_theme_initialize() {
// @todo Let the theme.negotiator listen to the kernel request event.
// Determine the active theme for the theme negotiator service. This includes
// the default theme as well as really specific ones like the ajax base theme.
- $request = \Drupal::request();
+ if (!$request) {
+ $request = \Drupal::request();
+ }
$theme = \Drupal::service('theme.negotiator')->determineActiveTheme($request);
// If no theme could be negotiated, or if the negotiated theme is not within
diff --git a/core/includes/utility.inc b/core/includes/utility.inc
index 6603166..135ab24 100644
--- a/core/includes/utility.inc
+++ b/core/includes/utility.inc
@@ -8,6 +8,9 @@
use Drupal\Component\Utility\Variable;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Cache\Cache;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+use Composer\Autoload\ClassLoader;
/**
* Drupal-friendly var_export().
@@ -32,34 +35,39 @@ function drupal_var_export($var, $prefix = '') {
*
* Requires DRUPAL_BOOTSTRAP_CONFIGURATION.
*
+ * @param \Composer\Autoload\ClassLoader $classloader
+ * The classloader.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ *
* @see rebuild.php
*/
-function drupal_rebuild() {
+function drupal_rebuild(ClassLoader $classloader, Request $request) {
// Remove Drupal's error and exception handlers; they rely on a working
// service container and other subsystems and will only cause a fatal error
// that hides the actual error.
restore_error_handler();
restore_exception_handler();
- // drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL) will build a new kernel. This
- // comes before DRUPAL_BOOTSTRAP_PAGE_CACHE.
+ // Force kernel to rebuild container.
PhpStorageFactory::get('service_container')->deleteAll();
PhpStorageFactory::get('twig')->deleteAll();
- // Disable the page cache.
- drupal_page_is_cacheable(FALSE);
-
// Bootstrap up to where caches exist and clear them.
- drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
+ $kernel = new DrupalKernel('prod', $classloader);
+ $kernel->prepareLegacyRequest($request);
+
foreach (Cache::getBins() as $bin) {
$bin->deleteAll();
}
- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ // Disable the page cache.
+ drupal_page_is_cacheable(FALSE);
+
drupal_flush_all_caches();
// Restore Drupal's error and exception handlers.
- // @see _drupal_bootstrap_configuration()
+ // @see \Drupal\Core\DrupalKernel::boot()
set_error_handler('_drupal_error_handler');
set_exception_handler('_drupal_exception_handler');
}
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index fe43d86..135ab43 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,21 +7,25 @@
namespace Drupal\Core;
-use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Component\Utility\Timer;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\BootstrapConfigStorageFactory;
use Drupal\Core\Config\NullStorage;
-use Drupal\Core\CoreServiceProvider;
+use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\DependencyInjection\YamlFileLoader;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Language\Language;
-use Symfony\Component\Config\Loader\LoaderInterface;
+use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Core\Site\Settings;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
+use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use Composer\Autoload\ClassLoader;
@@ -61,7 +65,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
*
* @var bool
*/
- protected $booted;
+ protected $booted = FALSE;
/**
* Holds the list of enabled modules.
@@ -164,14 +168,78 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
protected $serviceProviders;
/**
+ * Whether the request globals have been initialized.
+ *
+ * @var bool
+ */
+ protected static $isRequestInitialized = FALSE;
+
+ /**
+ * Whether the PHP environment has been initialized.
+ *
+ * This legacy phase can only be booted once because it sets session INI
+ * settings. If a session has already been started, re-generating these
+ * settings would break the session.
+ *
+ * @var bool
+ */
+ protected static $isEnvironmentInitialized = FALSE;
+
+ /**
+ * The site directory.
+ *
+ * @var string
+ */
+ protected $sitePath;
+
+ /**
+ * 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.
+ * @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) {
+ // Include our bootstrap file.
+ require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
+
+ $kernel = new static($environment, $class_loader, $allow_dumping);
+
+ // Ensure sane php environment variables..
+ static::bootEnvironment();
+
+ // Get our most basic settings setup.
+ $site_path = static::findSitePath($request);
+ $kernel->setSitePath($site_path);
+ Settings::initialize($site_path);
+
+ // 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
+ // settings.php file) and we are not already installing.
+ if (!Database::getConnectionInfo() && !drupal_installation_attempted() && !drupal_is_cli()) {
+ $response = new RedirectResponse($request->getBasePath() . '/core/install.php');
+ $response->prepare($request)->send();
+ }
+
+ return $kernel;
+ }
+
+ /**
* Constructs a DrupalKernel object.
*
* @param string $environment
- * 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'.
+ * String indicating the environment, e.g. 'prod' or 'dev'.
* @param \Composer\Autoload\ClassLoader $class_loader
- * (optional) The classloader is only used if $storage is not given or
+ * (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.
@@ -184,24 +252,156 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
*/
public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE, $allow_loading = NULL) {
$this->environment = $environment;
- $this->booted = FALSE;
$this->classLoader = $class_loader;
$this->allowDumping = $allow_dumping;
$this->allowLoading = isset($allow_loading) ? $allow_loading : $allow_dumping;
}
/**
+ * Returns the appropriate site directory for a request.
+ *
+ * Once the kernel has been created DrupalKernelInterface::getSitePath() is
+ * preferred since it gets the statically cached result of this method.
+ *
+ * Site directories contain all site specific code. This includes settings.php
+ * for bootstrap level configuration, file configuration stores, public file
+ * storage and site specific modules and themes.
+ *
+ * Finds a matching site directory file by stripping the website's hostname
+ * from left to right and pathname from right to left. By default, the
+ * directory must contain a 'settings.php' file for it to match. If the
+ * parameter $require_settings is set to FALSE, then a directory without a
+ * 'settings.php' file will match as well. The first configuration file found
+ * will be used and the remaining ones will be ignored. If no configuration
+ * file is found, returns a default value 'sites/default'. See
+ * default.settings.php for examples on how the URL is converted to a
+ * directory.
+ *
+ * If a file named sites.php is present in the sites directory, it will be
+ * loaded prior to scanning for directories. That file can define aliases in
+ * an associative array named $sites. The array is written in the format
+ * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
+ * directory alias for http://www.drupal.org:8080/mysite/test whose
+ * configuration file is in sites/example.com, the array should be defined as:
+ * @code
+ * $sites = array(
+ * '8080.www.drupal.org.mysite.test' => 'example.com',
+ * );
+ * @endcode
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ * @param bool $require_settings
+ * Only directories with an existing settings.php file will be recognized.
+ * Defaults to TRUE. During initial installation, this is set to FALSE so
+ * that Drupal can detect a matching directory, then create a new
+ * settings.php file in it.
+ *
+ * @return string
+ * The path of the matching directory.
+ *
+ * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
+ * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
+ * @see default.settings.php
+ * @see example.sites.php
+ */
+ public static function findSitePath(Request $request, $require_settings = TRUE) {
+ // Check for a simpletest override.
+ if ($test_prefix = drupal_valid_test_ua()) {
+ return 'sites/simpletest/' . substr($test_prefix, 10);
+ }
+
+ // Determine whether multi-site functionality is enabled.
+ if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
+ return 'sites/default';
+ }
+
+ // Otherwise, use find the site path using the request.
+ $script_name = $request->server->get('SCRIPT_NAME');
+ if (!$script_name) {
+ $script_name = $request->server->get('SCRIPT_FILENAME');
+ }
+ $http_host = $request->server->get('HTTP_HOST');
+
+ $sites = array();
+ include DRUPAL_ROOT . '/sites/sites.php';
+
+ $uri = explode('/', $script_name);
+ $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
+ for ($i = count($uri) - 1; $i > 0; $i--) {
+ for ($j = count($server); $j > 0; $j--) {
+ $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
+ if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
+ $dir = $sites[$dir];
+ }
+ if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
+ return "sites/$dir";
+ }
+ }
+ }
+ return 'sites/default';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSitePath($path) {
+ $this->sitePath = $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSitePath() {
+ return $this->sitePath;
+ }
+
+ /**
* {@inheritdoc}
*/
public function boot() {
if ($this->booted) {
- return;
+ return $this;
}
+
+ // 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';
+ require_once DRUPAL_ROOT . '/' . Settings::get('path_inc', 'core/includes/path.inc');
+ require_once DRUPAL_ROOT . '/core/includes/module.inc';
+ require_once DRUPAL_ROOT . '/core/includes/theme.inc';
+ require_once DRUPAL_ROOT . '/core/includes/pager.inc';
+ require_once DRUPAL_ROOT . '/' . Settings::get('menu_inc', 'core/includes/menu.inc');
+ require_once DRUPAL_ROOT . '/core/includes/tablesort.inc';
+ require_once DRUPAL_ROOT . '/core/includes/file.inc';
+ require_once DRUPAL_ROOT . '/core/includes/unicode.inc';
+ require_once DRUPAL_ROOT . '/core/includes/form.inc';
+ require_once DRUPAL_ROOT . '/core/includes/mail.inc';
+ require_once DRUPAL_ROOT . '/core/includes/ajax.inc';
+ require_once DRUPAL_ROOT . '/core/includes/errors.inc';
+ require_once DRUPAL_ROOT . '/core/includes/schema.inc';
+ require_once DRUPAL_ROOT . '/core/includes/entity.inc';
+
+ // Ensure that findSitePath is set.
+ if (!$this->sitePath) {
+ throw new \Exception('Kernel does not have site path set before calling boot()');
+ }
+ // Intialize the container.
$this->initializeContainer();
+
+ // Ensure mt_rand() is reseeded to prevent random values from one page load
+ // being exploited to predict random values in subsequent page loads.
+ $seed = unpack("L", Crypt::randomBytes(4));
+ mt_srand($seed[1]);
+
$this->booted = TRUE;
- if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, static::CONTAINER_BASE_CLASS)) {
- watchdog('DrupalKernel', 'Container cannot be written to disk');
- }
+
+ return $this;
}
/**
@@ -213,16 +413,104 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
}
$this->booted = FALSE;
$this->container = NULL;
+ $this->moduleList = NULL;
+ $this->moduleData = array();
}
/**
* {@inheritdoc}
*/
public function getContainer() {
+ if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, static::CONTAINER_BASE_CLASS)) {
+ watchdog('DrupalKernel', 'Container cannot be written to disk');
+ }
return $this->container;
}
/**
+ * Helper method that does request related initialization.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ */
+ protected function preHandle(Request $request) {
+ // Load all enabled modules.
+ $this->container->get('module_handler')->loadAll();
+
+ // Initialize legacy request globals.
+ $this->initializeRequestGlobals($request);
+
+ // Initialize cookie globals.
+ $this->initializeCookieGlobals($request);
+
+ // Ensure container has a request scope so we can load file stream wrappers.
+ if (!$this->container->isScopeActive('request')) {
+ // Enter the request scope so that current_user service is available for
+ // locale/translation sake.
+ $this->container->enterScope('request');
+ $this->container->set('request', $request, 'request');
+ $this->container->get('request_stack')->push($request);
+ }
+
+ // Make sure all stream wrappers are registered.
+ file_get_stream_wrappers();
+
+ // Back out scope required to initialize the file stream wrappers.
+ if ($this->container->isScopeActive('request')) {
+ $this->container->leaveScope('request');
+ }
+
+ // Set the allowed protocols once we have the config available.
+ $allowed_protocols = $this->container->get('config.factory')->get('system.filter')->get('protocols');
+ if (!isset($allowed_protocols)) {
+ // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by
+ // the installer and update.php, in which case the configuration may not
+ // exist (yet). Provide a minimal default set of allowed protocols for
+ // these cases.
+ $allowed_protocols = array('http', 'https');
+ }
+ UrlHelper::setAllowedProtocols($allowed_protocols);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @todo Invoke proper request/response/terminate events.
+ */
+ public function handlePageCache(Request $request) {
+ $this->boot();
+ $this->initializeCookieGlobals($request);
+
+ // Check for a cache mode force from settings.php.
+ if (Settings::get('page_cache_without_database')) {
+ $cache_enabled = TRUE;
+ }
+ else {
+ $config = $this->getContainer()->get('config.factory')->get('system.performance');
+ $cache_enabled = $config->get('cache.page.use_internal');
+ }
+
+ // If there is no session cookie and cache is enabled (or forced), try to
+ // serve a cached page.
+ if (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) {
+ // Get the page from the cache.
+ $response = drupal_page_get_cache($request);
+ // If there is a cached page, display it.
+ if ($response) {
+ $response->headers->set('X-Drupal-Cache', 'HIT');
+
+ drupal_serve_page_from_cache($response, $request);
+
+ // We are done.
+ $response->prepare($request);
+ $response->send();
+ exit;
+ }
+ }
+ return $this;
+ }
+
+ /**
* {@inheritdoc}
*/
public function discoverServiceProviders() {
@@ -246,14 +534,14 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
$this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($module_filenames));
// Load each module's serviceProvider class.
- foreach ($this->moduleList as $module => $weight) {
+ foreach ($module_filenames as $module => $filename) {
$camelized = ContainerBuilder::camelize($module);
$name = "{$camelized}ServiceProvider";
$class = "Drupal\\{$module}\\{$name}";
if (class_exists($class)) {
$this->serviceProviderClasses['app'][$module] = $class;
}
- $filename = dirname($module_filenames[$module]) . "/$module.services.yml";
+ $filename = dirname($filename) . "/$module.services.yml";
if (file_exists($filename)) {
$this->serviceYamls['app'][$module] = $filename;
}
@@ -270,7 +558,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
if (!empty($GLOBALS['conf']['container_yamls'])) {
$this->serviceYamls['site'] = $GLOBALS['conf']['container_yamls'];
}
- if (file_exists($site_services_yml = conf_path() . '/services.yml')) {
+ if (file_exists($site_services_yml = $this->getSitePath() . '/services.yml')) {
$this->serviceYamls['site'][] = $site_services_yml;
}
}
@@ -298,15 +586,28 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
/**
* {@inheritdoc}
*/
- public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = TRUE) {
- if (FALSE === $this->booted) {
- $this->boot();
- }
-
+ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+ $this->boot();
+ $this->preHandle($request);
return $this->getHttpKernel()->handle($request, $type, $catch);
}
/**
+ * {@inheritdoc}
+ */
+ public function prepareLegacyRequest(Request $request) {
+ $this->boot();
+ $this->preHandle($request);
+ // Enter the request scope so that current_user service is available for
+ // locale/translation sake.
+ $this->container->enterScope('request');
+ $this->container->set('request', $request);
+ $this->container->get('request_stack')->push($request);
+ $this->container->get('router.request_context')->fromRequest($request);
+ return $this;
+ }
+
+ /**
* Returns module data on the filesystem.
*
* @param $module
@@ -470,6 +771,215 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
}
/**
+ * Setup a consistent PHP environment.
+ *
+ * This method sets PHP environment options we want to be sure are set
+ * correctly for security or just saneness.
+ */
+ public static function bootEnvironment() {
+ if (static::$isEnvironmentInitialized) {
+ return;
+ }
+
+ // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
+ error_reporting(E_STRICT | E_ALL);
+
+ // Override PHP settings required for Drupal to work properly.
+ // sites/default/default.settings.php contains more runtime settings.
+ // The .htaccess file contains settings that cannot be changed at runtime.
+
+ // Use session cookies, not transparent sessions that puts the session id in
+ // the query string.
+ ini_set('session.use_cookies', '1');
+ ini_set('session.use_only_cookies', '1');
+ ini_set('session.use_trans_sid', '0');
+ // Don't send HTTP headers using PHP's session handler.
+ // Send an empty string to disable the cache limiter.
+ ini_set('session.cache_limiter', '');
+ // Use httponly session cookies.
+ ini_set('session.cookie_httponly', '1');
+
+ // Set sane locale settings, to ensure consistent string, dates, times and
+ // numbers handling.
+ setlocale(LC_ALL, 'C');
+
+ // Detect string handling method.
+ Unicode::check();
+
+ // Indicate that code is operating in a test child site.
+ if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
+ if ($test_prefix = drupal_valid_test_ua()) {
+ // Only code that interfaces directly with tests should rely on this
+ // constant; e.g., the error/exception handler conditionally adds further
+ // error information into HTTP response headers that are consumed by
+ // Simpletest's internal browser.
+ define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
+
+ // Log fatal errors to the test site directory.
+ ini_set('log_errors', 1);
+ ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
+ }
+ else {
+ // Ensure that no other code defines this.
+ define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
+ }
+ }
+
+ // Set the Drupal custom error handler.
+ set_error_handler('_drupal_error_handler');
+ set_exception_handler('_drupal_exception_handler');
+
+ static::$isEnvironmentInitialized = TRUE;
+ }
+
+ /**
+ * Bootstraps the legacy global request variables.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ *
+ * @todo D8: Eliminate this entirely in favor of Request object.
+ */
+ protected function initializeRequestGlobals(Request $request) {
+ // Provided by settings.php.
+ global $base_url;
+ // Set and derived from $base_url by this function.
+ global $base_path, $base_root, $script_path;
+ global $base_secure_url, $base_insecure_url;
+
+ // @todo Refactor with the Symfony Request object.
+ _current_path(request_path());
+
+ if (isset($base_url)) {
+ // Parse fixed base URL from settings.php.
+ $parts = parse_url($base_url);
+ if (!isset($parts['path'])) {
+ $parts['path'] = '';
+ }
+ $base_path = $parts['path'] . '/';
+ // Build $base_root (everything until first slash after "scheme://").
+ $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
+ }
+ else {
+ // Create base URL.
+ $http_protocol = $request->isSecure() ? 'https' : 'http';
+ $base_root = $http_protocol . '://' . $request->server->get('HTTP_HOST');
+
+ $base_url = $base_root;
+
+ // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
+ // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
+ if ($dir = rtrim(dirname($request->server->get('SCRIPT_NAME')), '\/')) {
+ // Remove "core" directory if present, allowing install.php, update.php,
+ // and others to auto-detect a base path.
+ $core_position = strrpos($dir, '/core');
+ if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
+ $base_path = substr($dir, 0, $core_position);
+ }
+ else {
+ $base_path = $dir;
+ }
+ $base_url .= $base_path;
+ $base_path .= '/';
+ }
+ else {
+ $base_path = '/';
+ }
+ }
+ $base_secure_url = str_replace('http://', 'https://', $base_url);
+ $base_insecure_url = str_replace('https://', 'http://', $base_url);
+
+ // Determine the path of the script relative to the base path, and add a
+ // trailing slash. This is needed for creating URLs to Drupal pages.
+ if (!isset($script_path)) {
+ $script_path = '';
+ // We don't expect scripts outside of the base path, but sanity check
+ // anyway.
+ if (strpos($request->server->get('SCRIPT_NAME'), $base_path) === 0) {
+ $script_path = substr($request->server->get('SCRIPT_NAME'), strlen($base_path)) . '/';
+ // If the request URI does not contain the script name, then clean URLs
+ // are in effect and the script path can be similarly dropped from URL
+ // generation. For servers that don't provide $_SERVER['REQUEST_URI'],
+ // we do not know the actual URI requested by the client, and
+ // request_uri() returns a URI with the script name, resulting in
+ // non-clean URLs unless
+ // there's other code that intervenes.
+ if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
+ $script_path = '';
+ }
+ // @todo Temporary BC for install.php, update.php, and other scripts.
+ // - http://drupal.org/node/1547184
+ // - http://drupal.org/node/1546082
+ if ($script_path !== 'index.php/') {
+ $script_path = '';
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Initialize cookie settings.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ *
+ * @todo D8: Eliminate this entirely in favor of a session object.
+ */
+ protected function initializeCookieGlobals(Request $request) {
+ // If we do this more then once per page request we are likely to cause
+ // errors.
+ if (static::$isRequestInitialized) {
+ return;
+ }
+ global $cookie_domain;
+
+ if ($cookie_domain) {
+ // If the user specifies the cookie domain, also use it for session name.
+ $session_name = $cookie_domain;
+ }
+ else {
+ // Otherwise use $base_url as session name, without the protocol
+ // to use the same session identifiers across HTTP and HTTPS.
+ $session_name = $request->getHost() . $request->getBasePath();
+ // Replace "core" out of session_name so core scripts redirect properly,
+ // specifically install.php and update.php.
+ $session_name = preg_replace('/\/core$/', '', $session_name);
+ // HTTP_HOST can be modified by a visitor, but has been sanitized already
+ // in DrupalKernel::bootEnvironment().
+ if ($cookie_domain = $request->server->get('HTTP_HOST')) {
+ // Strip leading periods, www., and port numbers from cookie domain.
+ $cookie_domain = ltrim($cookie_domain, '.');
+ if (strpos($cookie_domain, 'www.') === 0) {
+ $cookie_domain = substr($cookie_domain, 4);
+ }
+ $cookie_domain = explode(':', $cookie_domain);
+ $cookie_domain = '.' . $cookie_domain[0];
+ }
+ }
+ // Per RFC 2109, cookie domains must contain at least one dot other than the
+ // first. For hosts such as 'localhost' or IP Addresses we don't set a
+ // cookie domain.
+ if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
+ ini_set('session.cookie_domain', $cookie_domain);
+ }
+ // To prevent session cookies from being hijacked, a user can configure the
+ // SSL version of their website to only transfer session cookies via SSL by
+ // using PHP's session.cookie_secure setting. The browser will then use two
+ // separate session cookies for the HTTPS and HTTP versions of the site. So
+ // we must use different session identifiers for HTTPS and HTTP to prevent a
+ // cookie collision.
+ if ($request->isSecure()) {
+ ini_set('session.cookie_secure', TRUE);
+ }
+ $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
+
+ session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
+
+ static::$isRequestInitialized = TRUE;
+ }
+
+ /**
* Returns service instances to persist from an old container to a new one.
*/
protected function getServicesToPersist() {
@@ -634,7 +1144,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
/**
* Gets a http kernel from the container
*
- * @return HttpKernel
+ * @return \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected function getHttpKernel() {
return $this->container->get('http_kernel');
diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php
index 1e2ed07..08d007c 100644
--- a/core/lib/Drupal/Core/DrupalKernelInterface.php
+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
@@ -8,6 +8,7 @@
namespace Drupal\Core;
use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
/**
* The interface for DrupalKernel, the core of Drupal.
@@ -19,6 +20,8 @@ interface DrupalKernelInterface extends HttpKernelInterface {
/**
* Boots the current kernel.
+ *
+ * @return $this
*/
public function boot();
@@ -54,6 +57,22 @@ interface DrupalKernelInterface extends HttpKernelInterface {
public function getContainer();
/**
+ * Set the current site path.
+ *
+ * @param $path
+ * The current site path.
+ */
+ public function setSitePath($path);
+
+ /**
+ * Get the site path.
+ *
+ * @return string
+ * The current site path.
+ */
+ public function getSitePath();
+
+ /**
* Updates the kernel's list of modules to the new list.
*
* The kernel needs to update its bundle list and container to match the new
@@ -65,4 +84,28 @@ interface DrupalKernelInterface extends HttpKernelInterface {
* List of module filenames, keyed by module name.
*/
public function updateModules(array $module_list, array $module_filenames = array());
+
+ /**
+ * Attempts to serve a page from the cache.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ *
+ * @return $this
+ */
+ public function handlePageCache(Request $request);
+
+ /**
+ * Prepare the kernel for handling a request without handling the request.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The current request.
+ *
+ * @return $this
+ *
+ * @deprecated 8.x
+ * Only used by legacy front-controller scripts.
+ */
+ public function prepareLegacyRequest(Request $request);
+
}
diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
deleted file mode 100644
index aa7774e..0000000
--- a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\Core\EventSubscriber\LegacyRequestSubscriber.
- */
-
-namespace Drupal\Core\EventSubscriber;
-
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * KernelEvents::REQUEST event subscriber to initialize theme and modules.
- *
- * @todo Remove this subscriber when all of the code in it has been refactored.
- */
-class LegacyRequestSubscriber implements EventSubscriberInterface {
-
- /**
- * Initializes the rest of the legacy Drupal subsystems.
- *
- * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * The Event to process.
- */
- public function onKernelRequestLegacy(GetResponseEvent $event) {
- if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
- // Tell Drupal it is now fully bootstrapped (for the benefit of code that
- // calls drupal_get_bootstrap_phase()), but without having
- // _drupal_bootstrap_full() do anything, since we've already done the
- // equivalent above and in earlier listeners.
- _drupal_bootstrap_full(TRUE);
- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
- }
- }
-
- /**
- * Initializes the theme system after the routing system.
- *
- * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
- * The Event to process.
- */
- public function onKernelRequestLegacyAfterRouting(GetResponseEvent $event) {
- if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
- drupal_theme_initialize();
- }
- }
-
- /**
- * Registers the methods in this class that should be listeners.
- *
- * @return array
- * An array of event listener definitions.
- */
- static function getSubscribedEvents() {
- $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacy', 90);
- // Initialize the theme system after the routing system.
- $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacyAfterRouting', 30);
-
- return $events;
- }
-}
diff --git a/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
new file mode 100644
index 0000000..37ddfbb
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Initializes the theme for the current request.
+ */
+class ThemeNegotiatorRequestSubscriber implements EventSubscriberInterface {
+
+ /**
+ * Initializes the theme system after the routing system.
+ *
+ * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+ * The Event to process.
+ */
+ public function onKernelRequestThemeNegotiator(GetResponseEvent $event) {
+ if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+ if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
+ // @todo Refactor drupal_theme_initialize() into a request subscriber.
+ // @see https://drupal.org/node/2228093
+ drupal_theme_initialize($event->getRequest());
+ }
+ }
+ }
+
+ /**
+ * Registers the methods in this class that should be listeners.
+ *
+ * @return array
+ * An array of event listener definitions.
+ */
+ public static function getSubscribedEvents() {
+ $events[KernelEvents::REQUEST][] = array('onKernelRequestThemeNegotiator', 29);
+ return $events;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Site/Settings.php b/core/lib/Drupal/Core/Site/Settings.php
index 3ac0f03..e2d57d2 100644
--- a/core/lib/Drupal/Core/Site/Settings.php
+++ b/core/lib/Drupal/Core/Site/Settings.php
@@ -7,6 +7,8 @@
namespace Drupal\Core\Site;
+use Drupal\Core\Database\Database;
+
/**
* Read only settings that are initialized with the class.
*
@@ -81,6 +83,31 @@ final class Settings {
}
/**
+ * Bootstraps settings.php and the Settings singleton.
+ *
+ * @param string $site_path
+ * The current site path.
+ */
+ public static function initialize($site_path) {
+ // Export these settings.php variables to the global namespace.
+ global $base_url, $cookie_domain, $config_directories, $config;
+ $settings = array();
+ $config = array();
+ $databases = array();
+
+ // Make conf_path() available as local variable in settings.php.
+ if (is_readable(DRUPAL_ROOT . '/' . $site_path . '/settings.php')) {
+ require DRUPAL_ROOT . '/' . $site_path . '/settings.php';
+ }
+
+ // Initialize Database.
+ Database::setMultipleConnectionInfo($databases);
+
+ // Initialize Settings.
+ new Settings($settings);
+ }
+
+ /**
* Gets a salt useful for hardening against SQL injection.
*
* @return string
diff --git a/core/lib/Drupal/Core/Test/TestKernel.php b/core/lib/Drupal/Core/Test/TestKernel.php
index 12938ce..6144dbf 100644
--- a/core/lib/Drupal/Core/Test/TestKernel.php
+++ b/core/lib/Drupal/Core/Test/TestKernel.php
@@ -8,46 +8,28 @@
namespace Drupal\Core\Test;
use Drupal\Core\DrupalKernel;
-use Drupal\Core\Extension\Extension;
-use Drupal\Core\Installer\InstallerServiceProvider;
+use Symfony\Component\HttpFoundation\Request;
use Composer\Autoload\ClassLoader;
/**
- * Kernel for run-tests.sh.
+ * Kernel to mock requests to test simpletest.
*/
class TestKernel extends DrupalKernel {
/**
- * Constructs a TestKernel.
- *
- * @param \Composer\Autoload\ClassLoader $class_loader
- * The classloader.
- */
- public function __construct(ClassLoader $class_loader) {
- parent::__construct('test_runner', $class_loader, FALSE);
-
- // Prime the module list and corresponding Extension objects.
- // @todo Remove System module. Needed because \Drupal\Core\Datetime\Date
- // has a (needless) dependency on the 'date_format' entity, so calls to
- // format_date()/format_interval() cause a plugin not found exception.
- $this->moduleList = array(
- 'system' => 0,
- 'simpletest' => 0,
- );
- $this->moduleData = array(
- 'system' => new Extension('module', 'core/modules/system/system.info.yml', 'system.module'),
- 'simpletest' => new Extension('module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
- );
- }
-
- /**
* {@inheritdoc}
*/
- public function discoverServiceProviders() {
- parent::discoverServiceProviders();
- // The test runner does not require an installed Drupal site to exist.
- // Therefore, its environment is identical to that of the early installer.
- $this->serviceProviderClasses['app']['Test'] = 'Drupal\Core\Installer\InstallerServiceProvider';
+ public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment, $allow_dumping = TRUE) {
+ // Include our bootstrap file.
+ require_once __DIR__ . '/../../../../includes/bootstrap.inc';
+
+ // Exit if we should be in a test environment but aren't.
+ if (!drupal_valid_test_ua()) {
+ header($request->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
+ exit;
+ }
+
+ return parent::createFromRequest($request, $class_loader, $environment, $allow_dumping);
}
}
diff --git a/core/lib/Drupal/Core/Test/TestRunnerKernel.php b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
new file mode 100644
index 0000000..7b04673
--- /dev/null
+++ b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Test\TestRunnerKernel.
+ */
+
+namespace Drupal\Core\Test;
+
+use Drupal\Core\DrupalKernel;
+use Drupal\Core\Extension\Extension;
+use Drupal\Core\Installer\InstallerServiceProvider;
+use Composer\Autoload\ClassLoader;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Kernel for run-tests.sh.
+ */
+class TestRunnerKernel extends DrupalKernel {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment = 'test_runner', $allow_dumping = TRUE) {
+ return parent::createFromRequest($request, $class_loader, $environment);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($environment, ClassLoader $class_loader) {
+ parent::__construct($environment, $class_loader, FALSE);
+
+ // Prime the module list and corresponding Extension objects.
+ // @todo Remove System module. Needed because \Drupal\Core\Datetime\Date
+ // has a (needless) dependency on the 'date_format' entity, so calls to
+ // format_date()/format_interval() cause a plugin not found exception.
+ $this->moduleList = array(
+ 'system' => 0,
+ 'simpletest' => 0,
+ );
+ $this->moduleData = array(
+ 'system' => new Extension('module', 'core/modules/system/system.info.yml', 'system.module'),
+ 'simpletest' => new Extension('module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function boot() {
+ // Ensure that required Settings exist.
+ if (!Settings::getAll()) {
+ new Settings(array(
+ 'hash_salt' => 'run-tests',
+ ));
+ }
+
+ // Remove Drupal's error/exception handlers; they are designed for HTML
+ // and there is no storage nor a (watchdog) logger here.
+ restore_error_handler();
+ restore_exception_handler();
+
+ // In addition, ensure that PHP errors are not hidden away in logs.
+ ini_set('display_errors', TRUE);
+
+ parent::boot();
+
+ $this->getContainer()->get('module_handler')->loadAll();
+
+ simpletest_classloader_register();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function discoverServiceProviders() {
+ parent::discoverServiceProviders();
+ // The test runner does not require an installed Drupal site to exist.
+ // Therefore, its environment is identical to that of the early installer.
+ $this->serviceProviderClasses['app']['Test'] = 'Drupal\Core\Installer\InstallerServiceProvider';
+ }
+
+}
diff --git a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
index e4231a3..ec00177 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
@@ -122,6 +122,8 @@ class CKEditorLoadingTest extends WebTestBase {
// configuration also results in modified CKEditor configuration, so we
// don't test that here.
\Drupal::moduleHandler()->install(array('ckeditor_test'));
+ // Force container rebuild so module list is correct on request.
+ $this->rebuildContainer();
$this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
$editor_settings = $editor->getSettings();
$editor_settings['toolbar']['buttons'][0][] = 'Llama';
@@ -129,12 +131,14 @@ class CKEditorLoadingTest extends WebTestBase {
$editor->save();
$this->drupalGet('node/add/article');
list($settings, $editor_settings_present, $editor_js_present, $body, $format_selector) = $this->getThingsToCheck();
- $expected = array('formats' => array('filtered_html' => array(
- 'format' => 'filtered_html',
- 'editor' => 'ckeditor',
- 'editorSettings' => $ckeditor_plugin->getJSSettings($editor),
- 'editorSupportsContentFiltering' => TRUE,
- 'isXssSafe' => FALSE,
+ $expected = array(
+ 'formats' => array(
+ 'filtered_html' => array(
+ 'format' => 'filtered_html',
+ 'editor' => 'ckeditor',
+ 'editorSettings' => $ckeditor_plugin->getJSSettings($editor),
+ 'editorSupportsContentFiltering' => TRUE,
+ 'isXssSafe' => FALSE,
)));
$this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
$this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php
index 84c05cf..0cb7d3c 100644
--- a/core/modules/dblog/src/Tests/DbLogTest.php
+++ b/core/modules/dblog/src/Tests/DbLogTest.php
@@ -138,7 +138,7 @@ class DbLogTest extends WebTestBase {
'user' => $this->big_user,
'uid' => $this->big_user->id(),
'request_uri' => $base_root . request_uri(),
- 'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
+ 'referer' => \Drupal::request()->server->get('HTTP_REFERER'),
'ip' => '127.0.0.1',
'timestamp' => REQUEST_TIME,
);
@@ -421,7 +421,7 @@ class DbLogTest extends WebTestBase {
'user' => $this->big_user,
'uid' => $this->big_user->id(),
'request_uri' => $base_root . request_uri(),
- 'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
+ 'referer' => \Drupal::request()->server->get('HTTP_REFERER'),
'ip' => '127.0.0.1',
'timestamp' => REQUEST_TIME,
);
diff --git a/core/modules/field/src/Tests/FieldHelpTest.php b/core/modules/field/src/Tests/FieldHelpTest.php
index 0f976e0..2af6b92 100644
--- a/core/modules/field/src/Tests/FieldHelpTest.php
+++ b/core/modules/field/src/Tests/FieldHelpTest.php
@@ -56,6 +56,7 @@ class FieldHelpTest extends WebTestBase {
// Enable the Options, E-mail and Field API Test modules.
\Drupal::moduleHandler()->install(array('options', 'field_test'));
+ $this->rebuildContainer();
\Drupal::service('plugin.manager.field.widget')->clearCachedDefinitions();
\Drupal::service('plugin.manager.field.field_type')->clearCachedDefinitions();
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index e735ce3..6fa42f9 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -7,7 +7,10 @@
namespace Drupal\simpletest;
+use Drupal\Core\DrupalKernel;
use Drupal\Core\Session\UserSession;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
/**
* Base class for testing the interactive installer.
@@ -109,7 +112,8 @@ abstract class InstallerTestBase extends WebTestBase {
$this->setUpSite();
// Import new settings.php written by the installer.
- drupal_settings_initialize();
+ $request = Request::createFromGlobals();
+ Settings::initialize(DrupalKernel::findSitePath($request));
foreach ($GLOBALS['config_directories'] as $type => $path) {
$this->configDirectories[$type] = $path;
}
@@ -121,12 +125,14 @@ abstract class InstallerTestBase extends WebTestBase {
// 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->rebuildContainer();
+ $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', FALSE);
+ $this->kernel->prepareLegacyRequest($request);
+ $this->container = $this->kernel->getContainer();
+ $config = $this->container->get('config.factory');
// Manually configure the test mail collector implementation to prevent
// tests from sending out e-mails and collect them in state instead.
- \Drupal::config('system.mail')
+ $config->get('system.mail')
->set('interface.default', 'test_mail_collector')
->save();
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index 409c1b9..7a76b5b 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -13,6 +13,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DrupalKernel;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Language\Language;
+use Drupal\Core\Site\Settings;
use Drupal\Core\Entity\Schema\EntitySchemaProviderInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\Request;
@@ -131,23 +132,31 @@ abstract class KernelTestBase extends UnitTestBase {
// Create and set new configuration directories.
$this->prepareConfigDirectories();
- // Build a minimal, partially mocked environment for unit tests.
- $this->containerBuild(\Drupal::getContainer());
- // Make sure it survives kernel rebuilds.
+ // Add this test class as a service provider.
+ // @todo Remove the indirection; implement ServiceProviderInterface instead.
$GLOBALS['conf']['container_service_providers']['TestServiceProvider'] = 'Drupal\simpletest\TestServiceProvider';
- \Drupal::state()->set('system.module.files', $this->moduleFiles);
- \Drupal::state()->set('system.theme.files', $this->themeFiles);
-
- // Bootstrap the kernel.
- // No need to dump it; this test runs in-memory.
- $this->kernel = new DrupalKernel('unit_testing', drupal_classloader(), FALSE);
+ // 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);
+ $request = Request::create('/');
+ $this->kernel->setSitePath(DrupalKernel::findSitePath($request));
$this->kernel->boot();
- $request = Request::create('/');
+ // Restore and merge settings.
+ // DrupalKernel::boot() initializes new Settings, and the containerBuild()
+ // method sets additional settings.
+ new Settings($settings + Settings::getAll());
+
+ // Set the request scope.
+ $this->container = $this->kernel->getContainer();
$this->container->set('request', $request);
$this->container->get('request_stack')->push($request);
+ $this->container->get('state')->set('system.module.files', $this->moduleFiles);
+ $this->container->get('state')->set('system.theme.files', $this->themeFiles);
+
// Create a minimal core.extension configuration object so that the list of
// enabled modules can be maintained allowing
// \Drupal\Core\Config\ConfigInstaller::installDefaultConfig() to work.
@@ -404,8 +413,7 @@ abstract class KernelTestBase extends UnitTestBase {
// Ensure isLoaded() is TRUE in order to make _theme() work.
// Note that the kernel has rebuilt the container; this $module_handler is
// no longer the $module_handler instance from above.
- $module_handler = $this->container->get('module_handler');
- $module_handler->reload();
+ $this->container->get('module_handler')->reload();
$this->pass(format_string('Enabled modules: %modules.', array(
'%modules' => implode(', ', $modules),
)));
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 023cf8e..b133447 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -15,7 +15,6 @@ use Drupal\Core\Config\StorageComparer;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Database\ConnectionNotDefinedException;
use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\DrupalKernel;
use Drupal\Core\Language\Language;
use Drupal\Core\Session\AccountProxy;
use Drupal\Core\Session\AnonymousUserSession;
@@ -653,7 +652,7 @@ abstract class TestBase {
* TRUE if the assertion succeeded, FALSE otherwise.
*
* @see TestBase::prepareEnvironment()
- * @see _drupal_bootstrap_configuration()
+ * @see \Drupal\Core\DrupalKernel::bootConfiguration()
*/
protected function assertNoErrorsLogged() {
// Since PHP only creates the error.log file when an actual error is
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index ec50d4d..e75411d 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -20,6 +20,7 @@ use Drupal\Core\Language\Language;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Session\UserSession;
+use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\block\Entity\Block;
@@ -173,6 +174,8 @@ abstract class WebTestBase extends TestBase {
/**
* The kernel used in this test.
+ *
+ * @var \Drupal\Core\DrupalKernel
*/
protected $kernel;
@@ -844,17 +847,11 @@ abstract class WebTestBase extends TestBase {
);
$this->writeSettings($settings);
- // 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.
- drupal_settings_initialize();
-
// 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.
- drupal_settings_initialize();
foreach ($GLOBALS['config_directories'] as $type => $path) {
$this->configDirectories[$type] = $path;
}
@@ -867,7 +864,11 @@ abstract class WebTestBase extends TestBase {
// Not using File API; a potential error must trigger a PHP warning.
chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
- $this->rebuildContainer();
+ $request = \Drupal::request();
+ $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', TRUE);
+ $this->kernel->prepareLegacyRequest($request);
+ $container = $this->kernel->getContainer();
+ $config = $container->get('config.factory');
// Manually create and configure private and temporary files directories.
// While these could be preset/enforced in settings.php like the public
@@ -875,7 +876,7 @@ abstract class WebTestBase extends TestBase {
// UI. If declared in settings.php, they would no longer be configurable.
file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
- \Drupal::config('system.file')
+ $config->get('system.file')
->set('path.private', $this->private_files_directory)
->set('path.temporary', $this->temp_files_directory)
->save();
@@ -884,7 +885,7 @@ abstract class WebTestBase extends TestBase {
// tests from sending out e-mails and collect them in state instead.
// While this should be enforced via settings.php prior to installation,
// some tests expect to be able to test mail system implementations.
- \Drupal::config('system.mail')
+ $config->get('system.mail')
->set('interface.default', 'test_mail_collector')
->save();
@@ -892,10 +893,10 @@ abstract class WebTestBase extends TestBase {
// environment optimizations for all tests to avoid needless overhead and
// ensure a sane default experience for test authors.
// @see https://drupal.org/node/2259167
- \Drupal::config('system.logging')
+ $config->get('system.logging')
->set('error_level', 'verbose')
->save();
- \Drupal::config('system.performance')
+ $config->get('system.performance')
->set('css.preprocess', FALSE)
->set('js.preprocess', FALSE)
->save();
@@ -915,22 +916,20 @@ abstract class WebTestBase extends TestBase {
}
if ($modules) {
$modules = array_unique($modules);
- $success = \Drupal::moduleHandler()->install($modules, TRUE);
+ $success = $container->get('module_handler')->install($modules, TRUE);
$this->assertTrue($success, String::format('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
$this->rebuildContainer();
}
- // Like DRUPAL_BOOTSTRAP_CONFIGURATION above, any further bootstrap phases
- // are not re-executed by the installer, as Drupal is bootstrapped already.
// Reset/rebuild all data structures after enabling the modules, primarily
// to synchronize all data structures and caches between the test runner and
// the child site.
// Affects e.g. file_get_stream_wrappers().
- // @see _drupal_bootstrap_code()
- // @see _drupal_bootstrap_full()
+ // @see \Drupal\Core\DrupalKernel::bootCode()
// @todo Test-specific setUp() methods may set up further fixtures; find a
// way to execute this after setUp() is done, or to eliminate it entirely.
$this->resetAll();
+ $this->kernel->prepareLegacyRequest($request);
// Temporary fix so that when running from run-tests.sh we don't get an
// empty current path which would indicate we're on the home page.
@@ -1085,29 +1084,18 @@ abstract class WebTestBase extends TestBase {
* tests can invoke this workaround when requiring services from newly
* enabled modules to be immediately available in the same request.
*/
- protected function rebuildContainer($environment = 'prod') {
- // Preserve the request object after the container rebuild.
+ protected function rebuildContainer() {
+ // Maintain the current global request object.
$request = \Drupal::request();
- // When called from InstallerTestBase, the current container is the minimal
- // container from TestBase::prepareEnvironment(), which does not contain a
- // request stack.
- if (\Drupal::getContainer()->initialized('request_stack')) {
- $request_stack = \Drupal::service('request_stack');
- }
- $this->kernel = new DrupalKernel($environment, drupal_classloader(), TRUE, FALSE);
- $this->kernel->boot();
+ // Rebuild the kernel and bring it back to a fully bootstrapped state.
+ $this->kernel->shutdown();
+ $this->kernel->prepareLegacyRequest($request);
+
// DrupalKernel replaces the container in \Drupal::getContainer() with a
// different object, so we need to replace the instance on this test class.
- $this->container = \Drupal::getContainer();
- // The current user is set in TestBase::prepareEnvironment().
- $this->container->set('request', $request);
- if (isset($request_stack)) {
- $this->container->set('request_stack', $request_stack);
- }
- else {
- $this->container->get('request_stack')->push($request);
- }
+ $this->container = $this->kernel->getContainer();
+
$this->container->get('current_user')->setAccount(\Drupal::currentUser());
// The request context is normally set by the router_listener from within
@@ -1429,7 +1417,7 @@ abstract class WebTestBase extends TestBase {
* TRUE if this test was instantiated in a request within the test site,
* FALSE otherwise.
*
- * @see _drupal_bootstrap_configuration()
+ * @see \Drupal\Core\DrupalKernel::bootConfiguration()
*/
protected function isInChildSite() {
return DRUPAL_TEST_IN_CHILD_SITE;
diff --git a/core/modules/statistics/statistics.php b/core/modules/statistics/statistics.php
index 85864e1..4d20046 100644
--- a/core/modules/statistics/statistics.php
+++ b/core/modules/statistics/statistics.php
@@ -5,15 +5,22 @@
* Handles counts of node views via AJAX with minimal bootstrap.
*/
-// Change the directory to the Drupal root.
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
chdir('../../..');
-// Load the Drupal bootstrap.
-require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
-require_once dirname(dirname(__DIR__)) . '/includes/bootstrap.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL);
+$autoloader = require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
+
+$kernel = DrupalKernel::createFromRequest(Request::createFromGlobals(), $autoloader, 'prod');
+$kernel->boot();
+
+$views = $kernel->getContainer()
+ ->get('config.factory')
+ ->get('statistics.settings')
+ ->get('count_content_views');
-if (\Drupal::config('statistics.settings')->get('count_content_views')) {
+if ($views) {
$nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
if ($nid) {
\Drupal::database()->merge('node_counter')
diff --git a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
index 17e4b4b..9ec9df9 100644
--- a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
+++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
@@ -10,12 +10,18 @@ namespace Drupal\system\Tests\DrupalKernel;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\DrupalUnitTestBase;
+use Symfony\Component\HttpFoundation\Request;
/**
* Tests compilation of the DIC.
*/
class DrupalKernelTest extends DrupalUnitTestBase {
+ /**
+ * @var \Composer\Autoload\ClassLoader
+ */
+ protected $classloader;
+
public static function getInfo() {
return array(
'name' => 'DrupalKernel tests',
@@ -38,25 +44,60 @@ class DrupalKernelTest extends DrupalUnitTestBase {
'directory' => DRUPAL_ROOT . '/' . $this->public_files_directory . '/php',
'secret' => drupal_get_hash_salt(),
)));
+
+ $this->classloader = drupal_classloader();
+ }
+
+ /**
+ * Build a kernel for testings.
+ *
+ * Because the bootstrap is in DrupalKernel::boot and that involved loading
+ * settings from the filesystem we need to go to extra lengths to build a kernel
+ * for testing.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * A request object to use in booting the kernel.
+ * @param array $modules_enabled
+ * A list of modules to enable on the kernel.
+ * @param bool $read_only
+ * Build the kernel in a read only state.
+ * @return DrupalKernel
+ */
+ 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');
+ $this->settingsSet('hash_salt', $this->databasePrefix);
+ if (isset($modules_enabled)) {
+ $kernel->updateModules($modules_enabled);
+ }
+ $kernel->boot();
+
+ if ($read_only) {
+ $php_storage = Settings::get('php_storage');
+ $php_storage['service_container']['class'] = 'Drupal\Component\PhpStorage\FileReadOnlyStorage';
+ $this->settingsSet('php_storage', $php_storage);
+ }
+ return $kernel;
}
/**
* Tests DIC compilation.
*/
function testCompileDIC() {
- $classloader = drupal_classloader();
// @todo: write a memory based storage backend for testing.
- $module_enabled = array(
+ $modules_enabled = array(
'system' => 'system',
'user' => 'user',
);
- $kernel = new DrupalKernel('testing', $classloader);
- $kernel->updateModules($module_enabled);
- $kernel->boot();
+
+ $request = Request::createFromGlobals();
+ $this->getTestKernel($request, $modules_enabled)
+ // Trigger Kernel dump.
+ ->getContainer();
+
// Instantiate it a second time and we should get the compiled Container
// class.
- $kernel = new DrupalKernel('testing', $classloader);
- $kernel->boot();
+ $kernel = $this->getTestKernel($request);
$container = $kernel->getContainer();
$refClass = new \ReflectionClass($container);
$is_compiled_container =
@@ -66,25 +107,24 @@ class DrupalKernelTest extends DrupalUnitTestBase {
// Verify that the list of modules is the same for the initial and the
// compiled container.
$module_list = array_keys($container->get('module_handler')->getModuleList());
- $this->assertEqual(array_values($module_enabled), $module_list);
+ $this->assertEqual(array_values($modules_enabled), $module_list);
// Now use the read-only storage implementation, simulating a "production"
// environment.
- $php_storage = Settings::get('php_storage');
- $php_storage['service_container']['class'] = 'Drupal\Component\PhpStorage\FileReadOnlyStorage';
- $this->settingsSet('php_storage', $php_storage);
- $kernel = new DrupalKernel('testing', $classloader);
- $kernel->boot();
- $container = $kernel->getContainer();
+ $container = $this->getTestKernel($request, NULL, TRUE)
+ ->getContainer();
+
$refClass = new \ReflectionClass($container);
$is_compiled_container =
$refClass->getParentClass()->getName() == 'Drupal\Core\DependencyInjection\Container' &&
!$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$this->assertTrue($is_compiled_container);
+
// Verify that the list of modules is the same for the initial and the
// compiled container.
$module_list = array_keys($container->get('module_handler')->getModuleList());
- $this->assertEqual(array_values($module_enabled), $module_list);
+ $this->assertEqual(array_values($modules_enabled), $module_list);
+
// Test that our synthetic services are there.
$classloader = $container->get('class_loader');
$refClass = new \ReflectionClass($classloader);
@@ -98,25 +138,26 @@ class DrupalKernelTest extends DrupalUnitTestBase {
// Add another module so that we can test that the new module's bundle is
// registered to the new container.
- $module_enabled['service_provider_test'] = 'service_provider_test';
- $kernel = new DrupalKernel('testing', $classloader);
- $kernel->updateModules($module_enabled);
- $kernel->boot();
+ $modules_enabled['service_provider_test'] = 'service_provider_test';
+ $this->getTestKernel($request, $modules_enabled, TRUE);
+
// Instantiate it a second time and we should still get a ContainerBuilder
// class because we are using the read-only PHP storage.
- $kernel = new DrupalKernel('testing', $classloader);
- $kernel->updateModules($module_enabled);
- $kernel->boot();
+ $kernel = $this->getTestKernel($request, $modules_enabled, TRUE);
$container = $kernel->getContainer();
+
$refClass = new \ReflectionClass($container);
$is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
- $this->assertTrue($is_container_builder);
+ $this->assertTrue($is_container_builder, 'Container is a builder');
+
// Assert that the new module's bundle was registered to the new container.
- $this->assertTrue($container->has('service_provider_test_class'));
+ $this->assertTrue($container->has('service_provider_test_class'), 'Container has test service');
+
// 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');
+
// Check that the location of the new module is registered.
$modules = $container->getParameter('container.modules');
$this->assertEqual($modules['service_provider_test'], array(
diff --git a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
index 4faec44..58e62bc 100644
--- a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
@@ -102,6 +102,8 @@ class EntityViewControllerTest extends WebTestBase {
// Enable the RDF module to ensure that two modules can add attributes to
// the same field item.
\Drupal::moduleHandler()->install(array('rdf'));
+ $this->rebuildContainer();
+
// Set an RDF mapping for the field_test_text field. This RDF mapping will
// be turned into RDFa attributes in the field item output.
$mapping = rdf_get_mapping('entity_test', 'entity_test');
diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
index 4383658..5825895 100644
--- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
@@ -312,6 +312,7 @@ class MenuRouterTest extends WebTestBase {
protected function doTestMenuOnRoute() {
\Drupal::moduleHandler()->install(array('router_test'));
\Drupal::service('router.builder')->rebuild();
+ $this->rebuildContainer();
$this->drupalGet('router_test/test2');
$this->assertLinkByHref('menu_no_title_callback');
diff --git a/core/modules/system/src/Tests/System/ScriptTest.php b/core/modules/system/src/Tests/System/ScriptTest.php
index 9ba2e5c..773cfa0 100644
--- a/core/modules/system/src/Tests/System/ScriptTest.php
+++ b/core/modules/system/src/Tests/System/ScriptTest.php
@@ -45,6 +45,14 @@ class ScriptTest extends DrupalUnitTestBase {
* Tests rebuild_token_calculator.sh.
*/
public function testRebuildTokenCalculatorSh() {
+ // The script requires a settings.php with a hash salt setting.
+ $filename = $this->siteDirectory . '/settings.php';
+ touch($filename);
+ $settings['settings']['hash_salt'] = (object) array(
+ 'value' => 'some_random_key',
+ 'required' => TRUE,
+ );
+ drupal_rewrite_settings($settings, $filename);
$_SERVER['argv'] = array(
'core/scripts/rebuild_token_calculator.sh',
);
diff --git a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
index 202ddd2..e5c33a1 100644
--- a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
+++ b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
@@ -69,6 +69,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
// Enable the theme_suggestions_test module to test modules implementing
// suggestions alter hooks.
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
$this->drupalGet('theme-test/general-suggestion-alter');
$this->assertText('Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_alter().');
}
@@ -90,6 +91,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
// Enable the theme_suggestions_test module to test modules implementing
// suggestions alter hooks.
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
$this->drupalGet('theme-test/suggestion-alter');
$this->assertText('Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_HOOK_alter().');
}
@@ -113,6 +115,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
// Ensure that the base hook is used to determine the suggestion alter hook.
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
$this->drupalGet('theme-test/specific-suggestion-alter');
$this->assertText('Template overridden based on suggestion alter hook determined by the base hook.');
$this->assertTrue(strpos($this->drupalGetContent(), 'theme_test_specific_suggestions__variant') < strpos($this->drupalGetContent(), 'theme_test_specific_suggestions__variant__foo'), 'Specific theme call is added to the suggestions array before the suggestions alter hook.');
@@ -135,6 +138,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
// Enable the theme_suggestions_test module to test modules implementing
// suggestions alter hooks.
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
$this->drupalGet('theme-test/function-suggestion-alter');
$this->assertText('Theme function overridden based on new theme suggestion provided by a module.');
}
@@ -151,6 +155,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
// the include file is always loaded. The file will always be included for
// the first request because the theme registry is being rebuilt.
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
$this->drupalGet('theme-test/suggestion-alter-include');
$this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for initial request.');
$this->drupalGet('theme-test/suggestion-alter-include');
@@ -169,6 +174,7 @@ class ThemeSuggestionsAlterTest extends WebTestBase {
->set('default', 'test_theme')
->save();
\Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+ $this->rebuildContainer();
// Send two requests so that we get all the messages we've set via
// drupal_set_message().
diff --git a/core/modules/system/tests/http.php b/core/modules/system/tests/http.php
index 662031f..3386979 100644
--- a/core/modules/system/tests/http.php
+++ b/core/modules/system/tests/http.php
@@ -5,19 +5,29 @@
* Fake an HTTP request, for use during testing.
*/
+use Drupal\Core\Test\TestKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+$autoloader = require_once './core/vendor/autoload.php';
+
// Set a global variable to indicate a mock HTTP request.
$is_http_mock = !empty($_SERVER['HTTPS']);
// Change to HTTP.
$_SERVER['HTTPS'] = NULL;
ini_set('session.cookie_secure', FALSE);
-foreach ($_SERVER as $key => $value) {
- $_SERVER[$key] = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
- $_SERVER[$key] = str_replace('https://', 'http://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+ $value = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
+ $value = str_replace('https://', 'http://', $value);
}
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
+$response = $kernel
+ ->handlePageCache($request)
+ ->handle($request)
+ // Handle the response object.
+ ->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/system/tests/https.php b/core/modules/system/tests/https.php
index 247e6e5..00a6b13 100644
--- a/core/modules/system/tests/https.php
+++ b/core/modules/system/tests/https.php
@@ -8,18 +8,28 @@
* see http.php.
*/
+use Drupal\Core\Test\TestKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+$autoloader = require_once './core/vendor/autoload.php';
+
// Set a global variable to indicate a mock HTTPS request.
$is_https_mock = empty($_SERVER['HTTPS']);
// Change to HTTPS.
$_SERVER['HTTPS'] = 'on';
-foreach ($_SERVER as $key => $value) {
- $_SERVER[$key] = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
- $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+ $value = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
+ $value = str_replace('http://', 'https://', $value);
}
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
+$response = $kernel
+ ->handlePageCache($request)
+ ->handle($request)
+ // Handle the response object.
+ ->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 3599c59..f46770a 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -109,7 +109,7 @@ function toolbar_element_info() {
* Use Drupal's page cache for toolbar/subtrees/*, even for authenticated users.
*
* This gets invoked after full bootstrap, so must duplicate some of what's
- * done by _drupal_bootstrap_page_cache().
+ * done by \Drupal\Core\DrupalKernel::handlePageCache().
*
* @todo Replace this hack with something better integrated with DrupalKernel
* once Drupal's page caching itself is properly integrated.
@@ -119,7 +119,7 @@ function _toolbar_initialize_page_cache() {
drupal_page_is_cacheable(TRUE);
// If we have a cache, serve it.
- // @see _drupal_bootstrap_page_cache()
+ // @see \Drupal\Core\DrupalKernel::handlePageCache()
$request = \Drupal::request();
$response = drupal_page_get_cache($request);
if ($response) {
diff --git a/core/modules/user/src/Tests/UserLoginTest.php b/core/modules/user/src/Tests/UserLoginTest.php
index 8016987..c6fefcf 100644
--- a/core/modules/user/src/Tests/UserLoginTest.php
+++ b/core/modules/user/src/Tests/UserLoginTest.php
@@ -135,6 +135,7 @@ class UserLoginTest extends WebTestBase {
// users password gets rehashed during the login.
$overridden_count_log2 = 19;
\Drupal::moduleHandler()->install(array('user_custom_phpass_params_test'));
+ $this->rebuildContainer();
$account->pass_raw = $password;
$this->drupalLogin($account);
diff --git a/core/modules/views_ui/src/Tests/PreviewTest.php b/core/modules/views_ui/src/Tests/PreviewTest.php
index 01feff6..315ef98 100644
--- a/core/modules/views_ui/src/Tests/PreviewTest.php
+++ b/core/modules/views_ui/src/Tests/PreviewTest.php
@@ -34,6 +34,8 @@ class PreviewTest extends UITestBase {
*/
protected function testPreviewContextual() {
\Drupal::moduleHandler()->install(array('contextual'));
+ $this->rebuildContainer();
+
$this->drupalGet('admin/structure/views/view/test_preview/edit');
$this->assertResponse(200);
$this->drupalPostForm(NULL, $edit = array(), t('Update preview'));
diff --git a/core/rebuild.php b/core/rebuild.php
index 3e8ed12..f7acbce 100644
--- a/core/rebuild.php
+++ b/core/rebuild.php
@@ -11,25 +11,30 @@
*/
use Drupal\Component\Utility\Crypt;
+use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
// Change the directory to the Drupal root.
chdir('..');
-require_once __DIR__ . '/vendor/autoload.php';
-require_once __DIR__ . '/includes/bootstrap.inc';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/includes/utility.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+$request = Request::createFromGlobals();
+// Manually resemble early bootstrap of DrupalKernel::boot().
+require_once __DIR__ . '/includes/bootstrap.inc';
+DrupalKernel::bootEnvironment();
+Settings::initialize(DrupalKernel::findSitePath($request));
if (Settings::get('rebuild_access', FALSE) ||
- (isset($_GET['token'], $_GET['timestamp']) &&
- ((REQUEST_TIME - $_GET['timestamp']) < 300) &&
- ($_GET['token'] === Crypt::hmacBase64($_GET['timestamp'], Settings::get('hash_salt')))
+ ($request->get('token') && $request->get('timestamp') &&
+ ((REQUEST_TIME - $request->get('timestamp')) < 300) &&
+ ($request->get('token') === Crypt::hmacBase64($request->get('timestamp'), Settings::get('hash_salt')))
)) {
- drupal_rebuild();
+ drupal_rebuild($autoloader, $request);
drupal_set_message('Cache rebuild complete.');
}
-
-header('Location: ' . $GLOBALS['base_url']);
+$base_path = dirname(dirname($request->getBaseUrl()));
+header('Location: ' . $base_path);
diff --git a/core/scripts/password-hash.sh b/core/scripts/password-hash.sh
index f80d75c..ee3c102 100755
--- a/core/scripts/password-hash.sh
+++ b/core/scripts/password-hash.sh
@@ -9,6 +9,7 @@
*/
use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
// Check for $_SERVER['argv'] instead of PHP_SAPI === 'cli' to allow this script
// to be tested with the Simpletest UI test runner.
@@ -56,14 +57,10 @@ EOF;
// Password list to be processed.
$passwords = $_SERVER['argv'];
-$core = dirname(__DIR__);
-require_once $core . '/vendor/autoload.php';
-require_once $core . '/includes/bootstrap.inc';
+$autoloader = require __DIR__ . '/../vendor/autoload.php';
-// Bootstrap the code so we have the container.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
-$kernel = new DrupalKernel('prod', drupal_classloader(), FALSE);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod', FALSE);
$kernel->boot();
$password_hasher = $kernel->getContainer()->get('password');
diff --git a/core/scripts/rebuild_token_calculator.sh b/core/scripts/rebuild_token_calculator.sh
index 9e7dc03..bcfd2b6 100755
--- a/core/scripts/rebuild_token_calculator.sh
+++ b/core/scripts/rebuild_token_calculator.sh
@@ -7,7 +7,9 @@
*/
use Drupal\Component\Utility\Crypt;
+use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
// Check for $_SERVER['argv'] instead of PHP_SAPI === 'cli' to allow this script
// to be tested with the Simpletest UI test runner.
@@ -16,11 +18,11 @@ if (!isset($_SERVER['argv']) || !is_array($_SERVER['argv'])) {
return;
}
-$core = dirname(__DIR__);
-require_once $core . '/vendor/autoload.php';
-require_once $core . '/includes/bootstrap.inc';
+require __DIR__ . '/../vendor/autoload.php';
+require_once __DIR__ . '/../includes/bootstrap.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+$request = Request::createFromGlobals();
+Settings::initialize(DrupalKernel::findSitePath($request));
$timestamp = time();
$token = Crypt::hmacBase64($timestamp, Settings::get('hash_salt'));
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 8eff2a2..4679325 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -8,10 +8,10 @@
use Drupal\Component\Utility\Timer;
use Drupal\Core\Database\Database;
use Drupal\Core\Site\Settings;
-use Drupal\Core\Test\TestKernel;
+use Drupal\Core\Test\TestRunnerKernel;
use Symfony\Component\HttpFoundation\Request;
-require_once __DIR__ . '/../vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/../vendor/autoload.php';
const SIMPLETEST_SCRIPT_COLOR_PASS = 32; // Green.
const SIMPLETEST_SCRIPT_COLOR_FAIL = 31; // Red.
@@ -26,7 +26,10 @@ if ($args['help'] || $count == 0) {
}
simpletest_script_init();
-simpletest_script_bootstrap();
+
+$request = Request::createFromGlobals();
+$kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
+$kernel->prepareLegacyRequest($request);
if ($args['execute-test']) {
simpletest_script_setup_database();
@@ -353,50 +356,6 @@ function simpletest_script_init() {
}
chdir(realpath(__DIR__ . '/../..'));
- require_once dirname(__DIR__) . '/includes/bootstrap.inc';
-}
-
-/**
- * Bootstraps a minimal Drupal environment.
- *
- * @see install_begin_request()
- */
-function simpletest_script_bootstrap() {
- // Load legacy include files.
- foreach (glob(DRUPAL_ROOT . '/core/includes/*.inc') as $include) {
- require_once $include;
- }
-
- drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
- // Remove Drupal's error/exception handlers; they are designed for HTML
- // and there is no storage nor a (watchdog) logger here.
- restore_error_handler();
- restore_exception_handler();
-
- // In addition, ensure that PHP errors are not hidden away in logs.
- ini_set('display_errors', TRUE);
-
- // Ensure that required Settings exist.
- if (!Settings::getAll()) {
- new Settings(array(
- 'hash_salt' => 'run-tests',
- ));
- }
-
- $kernel = new TestKernel(drupal_classloader());
- $kernel->boot();
-
- $request = Request::createFromGlobals();
- $container = $kernel->getContainer();
- $container->enterScope('request');
- $container->set('request', $request, 'request');
- $container->get('request_stack')->push($request);
-
- $module_handler = $container->get('module_handler');
- $module_handler->loadAll();
-
- simpletest_classloader_register();
}
/**
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index 72c5d5b..99fe34d 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -87,7 +87,7 @@ define('DRUPAL_ROOT', realpath(__DIR__ . '/../../'));
// Set sane locale settings, to ensure consistent string, dates, times and
// numbers handling.
-// @see drupal_environment_initialize()
+// @see \Drupal\Core\DrupalKernel::bootEnvironment()
setlocale(LC_ALL, 'C');
// Set the default timezone. While this doesn't cause any tests to fail, PHP
diff --git a/core/update.php b/core/update.php
index b6accf3..9147e9e 100644
--- a/core/update.php
+++ b/core/update.php
@@ -25,7 +25,7 @@ use Symfony\Component\DependencyInjection\Reference;
// Change the directory to the Drupal root.
chdir('..');
-require_once __DIR__ . '/vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
// Exit early if an incompatible PHP version would cause fatal errors.
// The minimum version is specified explicitly, as DRUPAL_MINIMUM_PHP is not
@@ -297,18 +297,17 @@ ini_set('display_errors', FALSE);
// We prepare a minimal bootstrap for the update requirements check to avoid
// reaching the PHP memory limit.
-require_once __DIR__ . '/includes/bootstrap.inc';
require_once __DIR__ . '/includes/update.inc';
-require_once __DIR__ . '/includes/common.inc';
-require_once __DIR__ . '/includes/file.inc';
-require_once __DIR__ . '/includes/unicode.inc';
require_once __DIR__ . '/includes/install.inc';
-require_once __DIR__ . '/includes/schema.inc';
-// Bootstrap to configuration.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-// Bootstrap the database.
-require_once __DIR__ . '/includes/database.inc';
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'update', FALSE);
+
+// Enable UpdateServiceProvider service overrides.
+// @see update_flush_all_caches()
+$GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
+$GLOBALS['conf']['update_service_provider_overrides'] = TRUE;
+$kernel->boot();
// Updating from a site schema version prior to 8000 should block the update
// process. Ensure that the site is not attempting to update a database
@@ -321,27 +320,9 @@ if (db_table_exists('system')) {
}
}
-// Enable UpdateServiceProvider service overrides.
-// @see update_flush_all_caches()
-$GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
-$GLOBALS['conf']['update_service_provider_overrides'] = TRUE;
-
-// module.inc is not yet loaded but there are calls to module_config_sort()
-// below.
-require_once __DIR__ . '/includes/module.inc';
-
-$settings = Settings::getAll();
-new Settings($settings);
-$kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
-$kernel->boot();
-$request = Request::createFromGlobals();
-$container = \Drupal::getContainer();
-$container->set('request', $request);
-$container->get('request_stack')->push($request);
+$kernel->prepareLegacyRequest($request);
// Determine if the current user has access to run update.php.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-
\Drupal::service('session_manager')->initialize();
// Ensure that URLs generated for the home and admin pages don't have 'update.php'
@@ -378,7 +359,6 @@ if (is_null($op) && update_access_allowed()) {
install_goto('core/update.php?op=info');
}
-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
drupal_maintenance_theme();
// Turn error reporting back on. From now on, only fatal errors (which are