diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 803947f..defc5c9 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -148,14 +148,15 @@ function install_state_defaults() { // The last task that was completed during the previous installation // request. 'completed_task' => NULL, - // This becomes TRUE only when a valid config directory is created or - // detected. + // TRUE when there are valid config directories. 'config_verified' => FALSE, - // This becomes TRUE only when Drupal's system module is installed. - 'database_tables_exist' => FALSE, - // This becomes TRUE only when a valid database connection can be - // established. + // TRUE when there is a valid database connection. 'database_verified' => FALSE, + // TRUE when a valid settings.php exists (containing both database + // connection information and config directory names). + 'settings_verified' => FALSE, + // TRUE when the base system is ready to operate. + 'base_system_verified' => FALSE, // Whether a translation file for the selected language will be downloaded // from the translation server. 'download_translation' => FALSE, @@ -199,10 +200,6 @@ function install_state_defaults() { // Tokens in the pattern will be replaced by appropriate values for the // required translation file. 'server_pattern' => 'http://ftp.drupal.org/files/translations/%core/%project/%project-%version.%language.po', - // This becomes TRUE only when a valid settings.php file is written - // (containing both valid database connection information and a valid - // config directory). - 'settings_verified' => FALSE, // Installation tasks can set this to TRUE to force the page request to // end (even if there is no themable output), in the case of an interactive // installation. This is needed only rarely; for example, it would be used @@ -284,74 +281,62 @@ function install_begin_request(&$install_state) { // This must go after drupal_bootstrap(), which unsets globals! global $conf; - require_once DRUPAL_ROOT . '/core/modules/system/system.install'; - require_once DRUPAL_ROOT . '/core/includes/common.inc'; + // Load include files containing procedural service helpers. + require_once DRUPAL_ROOT . '/core/includes/cache.inc'; + require_once DRUPAL_ROOT . '/core/includes/database.inc'; + + // Required for module_list() override in early installer environment. require_once DRUPAL_ROOT . '/core/includes/file.inc'; + require_once DRUPAL_ROOT . '/core/includes/module.inc'; + + // Required for various installer operations. require_once DRUPAL_ROOT . '/core/includes/install.inc'; - require_once DRUPAL_ROOT . '/core/includes/schema.inc'; - require_once DRUPAL_ROOT . '/' . settings()->get('path_inc', 'core/includes/path.inc'); - // Load module basics (needed for hook invokes). - include_once DRUPAL_ROOT . '/core/includes/module.inc'; - include_once DRUPAL_ROOT . '/core/includes/session.inc'; - require_once DRUPAL_ROOT . '/core/includes/entity.inc'; + // Required for running install tasks. + require_once DRUPAL_ROOT . '/core/includes/form.inc'; + require_once DRUPAL_ROOT . '/core/includes/ajax.inc'; + require_once DRUPAL_ROOT . '/core/includes/batch.inc'; + + // Determine bootstrap status. + if (!empty($install_state['parameters']['bootstrap'])) { + $install_state['parameters']['bootstrap'] = (int) $install_state['parameters']['bootstrap']; + $install_state['base_system_verified'] = TRUE; + } - // Determine whether the configuration system is ready to operate. + // Determine whether base system services are ready to operate. $install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY); - // Check existing settings.php. $install_state['database_verified'] = install_verify_database_settings(); $install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified']; - // If it is not, replace the configuration storage with the InstallStorage - // implementation, for the following reasons: - // - The first call into drupal_container() will try to set up the regular - // runtime configuration storage, using the CachedStorage by default. It - // calls config_get_config_directory() to retrieve the config directory to - // use, but that throws an exception, since $config_directories is not - // defined since there is no settings.php yet. If there is a prepared - // settings.php already, then the returned directory still cannot be used, - // because it does not necessarily exist. The installer ensures that it - // exists and is writeable in a later step. - // - The installer outputs maintenance theme pages and performs many other - // operations, which try to load configuration. Since there is no active - // configuration yet, and because the configuration system does not have a - // notion of default values at runtime, data is missing in many places. The - // lack of data does not trigger errors, but results in a broken user - // interface (e.g., missing page title, etc). - // - The actual configuration data to read during installation is essentially - // the default configuration provided by the installation profile and - // modules (most notably System module). The InstallStorage therefore reads - // from the default configuration directories of extensions. - // This override is reverted as soon as the config directory and the - // database has been set up successfully. - // @see drupal_install_config_directories() - // @see install_settings_form_submit() - if ($install_state['settings_verified']) { - $kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE); - $kernel->boot(); - } - else { + // If they are not, replace services with in-memory implementations and + // specialized installer implementations. This override is reverted as soon as + // the install_system_rebuild() phase is reached. + if (!$install_state['base_system_verified']) { // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. $container = new ContainerBuilder(); + // The actual configuration data to read during installation is essentially + // the default configuration provided by the installation profile and + // modules (most notably System module). The InstallStorage therefore reads + // from the default configuration directories of extensions. $container->register('event_dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher'); - $container->register('config.storage', 'Drupal\Core\Config\InstallStorage'); $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') ->addArgument(new Reference('config.storage')) ->addArgument(new Reference('event_dispatcher')); + // Register the 'language_manager' service. $container->register('language_manager', 'Drupal\Core\Language\LanguageManager'); - // The install process cannot use the database lock backend since the database - // is not fully up, so we use a null backend implementation during the - // installation process. This will also speed up the installation process. - // The site being installed will use the real lock backend when doing AJAX - // requests but, except for a WSOD, there is no chance for a a lock to stall - // (as opposed to the cache backend) so we can afford having a null - // implementation here. + $conf['keyvalue_default'] = 'keyvalue.memory'; + $container + ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory') + ->addArgument(new Reference('service_container')); + $container + ->register('keyvalue.memory', 'Drupal\Core\KeyValueStore\KeyValueMemoryFactory'); $container->register('lock', 'Drupal\Core\Lock\NullLockBackend'); + $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); // Register a module handler for managing enabled modules. $container @@ -368,22 +353,46 @@ function install_begin_request(&$install_state) { ->addMethodCall('setUserAgent', array('Drupal (+http://drupal.org/)')); drupal_container($container); + + $module_handler = drupal_container()->get('module_handler'); + if (!$module_handler->moduleExists('system')) { + // Override the module list with a minimal set of modules. + $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); + } + $module_handler->load('system'); + + // Set up $language, so t() caller functions will still work. + drupal_language_initialize(); } + // We have reached the install_system_rebuild() install task and need to + // install System module as well as all the rest of the system in a full + // environment. + else { + $kernel = new DrupalKernel('prod', TRUE, drupal_classloader(), FALSE); + $kernel->boot(); - // Set up $language, so t() caller functions will still work. - drupal_language_initialize(); - require_once DRUPAL_ROOT . '/core/includes/ajax.inc'; + // DRUPAL_BOOTSTRAP_SESSION is incompatible with the installer, as it tries + // to read and write sessions before the {users} table has been installed. + // Therefore, the install_base_system() task needs a custom bootstrap that + // avoids session initialization but is otherwise still a full environment. + // @todo Convert session handling into a swappable service. + // @see http://drupal.org/node/335411 + if ($install_state['parameters']['bootstrap'] == DRUPAL_BOOTSTRAP_VARIABLES) { + require_once DRUPAL_ROOT . '/core/includes/common.inc'; + drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES); + _drupal_bootstrap_code(); + } + else { + drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); + } - $module_handler = drupal_container()->get('module_handler'); - if (!$module_handler->moduleExists('system')) { - // Override the module list with a minimal set of modules. - $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); + // We are anonymous until we reach install_configure_form_submit(). + global $user; + if (empty($user)) { + $user = drupal_anonymous_user(); + } } - $module_handler->load('system'); - - require_once DRUPAL_ROOT . '/core/includes/cache.inc'; - $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); // Prepare for themed output. We need to run this at the beginning of the // page request to avoid a different theme accidentally getting set. (We also @@ -392,16 +401,8 @@ function install_begin_request(&$install_state) { // accessing the database before it is set up yet.) drupal_maintenance_theme(); - if ($install_state['database_verified']) { - // Initialize the database system. Note that the connection - // won't be initialized until it is actually requested. - require_once DRUPAL_ROOT . '/core/includes/database.inc'; - // Verify the last completed task in the database, if there is one. - $task = install_verify_completed_task(); - } - else { - $task = NULL; + if (!$install_state['database_verified']) { // Do not install over a configured settings.php. if (!empty($GLOBALS['databases'])) { @@ -410,8 +411,7 @@ function install_begin_request(&$install_state) { } // Modify the installation state as appropriate. - $install_state['completed_task'] = $task; - $install_state['database_tables_exist'] = !empty($task); + $install_state['completed_task'] = install_verify_completed_task(); // Add the list of available profiles to the installation state. $install_state['profiles'] += drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.profile$/', 'profiles'); @@ -455,8 +455,8 @@ function install_run_tasks(&$install_state) { if (!$install_state['task_not_complete']) { $install_state['tasks_performed'][] = $task_name; $install_state['installation_finished'] = empty($tasks_to_perform); - if ($install_state['database_tables_exist'] && ($task['run'] == INSTALL_TASK_RUN_IF_NOT_COMPLETED || $install_state['installation_finished'])) { - variable_set('install_task', $install_state['installation_finished'] ? 'done' : $task_name); + if ($task['run'] == INSTALL_TASK_RUN_IF_NOT_COMPLETED || $install_state['installation_finished']) { + state()->set('system.install_task', $install_state['installation_finished'] ? 'done' : $task_name); } } // Stop when there are no tasks left. In the case of an interactive @@ -484,7 +484,6 @@ function install_run_task($task, &$install_state) { $function = $task['function']; if ($task['type'] == 'form') { - require_once DRUPAL_ROOT . '/core/includes/form.inc'; if ($install_state['interactive']) { // For interactive forms, build the form and ensure that it will not // redirect, since the installer handles its own redirection only after @@ -529,7 +528,7 @@ function install_run_task($task, &$install_state) { elseif ($task['type'] == 'batch') { // Start a new batch based on the task function, if one is not running // already. - $current_batch = variable_get('install_current_batch'); + $current_batch = state()->get('system.install_current_batch'); if (!$install_state['interactive'] || !$current_batch) { $batch = $function($install_state); if (empty($batch)) { @@ -542,7 +541,7 @@ function install_run_task($task, &$install_state) { // task is currently running. Otherwise, we need to make sure the batch // will complete in one page request. if ($install_state['interactive']) { - variable_set('install_current_batch', $function); + state()->set('system.install_current_batch', $function); } else { $batch =& batch_get(); @@ -555,7 +554,6 @@ function install_run_task($task, &$install_state) { // If we are in the middle of processing this batch, keep sending back // any output from the batch process, until the task is complete. elseif ($current_batch == $function) { - include_once DRUPAL_ROOT . '/core/includes/batch.inc'; $output = _batch_page(); // Because Batch API now returns a JSON response for intermediary steps, // but the installer doesn't handle Response objects yet, just send the @@ -571,7 +569,7 @@ function install_run_task($task, &$install_state) { // longer requesting a batch ID. if ($output === FALSE) { // Return nothing so the next task will run in the same request. - variable_del('install_current_batch'); + state()->delete('system.install_current_batch'); return; } else { @@ -651,7 +649,6 @@ function install_tasks($install_state) { $tasks = array( 'install_select_language' => array( 'display_name' => st('Choose language'), - 'run' => INSTALL_TASK_RUN_IF_REACHED, ), 'install_download_translation' => array( 'run' => $needs_download ? INSTALL_TASK_RUN_IF_REACHED : INSTALL_TASK_SKIP, @@ -659,7 +656,6 @@ function install_tasks($install_state) { 'install_select_profile' => array( 'display_name' => st('Choose profile'), 'display' => count($install_state['profiles']) != 1, - 'run' => INSTALL_TASK_RUN_IF_REACHED, ), 'install_load_profile' => array( 'run' => INSTALL_TASK_RUN_IF_REACHED, @@ -675,10 +671,14 @@ function install_tasks($install_state) { // since the form submit handler is where settings.php is rewritten. 'run' => $install_state['settings_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, ), - 'install_base_system' => array( + 'install_system_schema' => array( + 'run' => $install_state['base_system_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, ), - 'install_bootstrap_full' => array( - 'run' => INSTALL_TASK_RUN_IF_REACHED, + 'install_system_rebuild' => array( + 'run' => $install_state['base_system_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, + ), + // All tasks below are executed in a regular, full Drupal environment. + 'install_base_system' => array( ), 'install_profile_modules' => array( 'display_name' => count($install_state['profiles']) == 1 ? st('Install site') : st('Installation profile'), @@ -873,15 +873,84 @@ function install_verify_requirements(&$install_state) { } /** + * Install task: Installs the System module schema. + */ +function install_system_schema(&$install_state) { + require_once DRUPAL_ROOT . '/core/includes/schema.inc'; + require_once DRUPAL_ROOT . '/core/modules/system/system.install'; + // This task is the one that sets up persistent storage tables. Since this + // task is executed in the early installer environment, install_run_tasks() + // is not able to record that this task has been completed. Thus, the + // interactive installer invokes this task a second time and the fact that it + // completed can only be recorded after the second invocation. + $schema = drupal_get_schema_unprocessed('system'); + $table = key($schema); + if (!db_table_exists($table)) { + drupal_install_schema('system'); + } + + // If we are in the interactive installer, all we need to do is to set the + // 'bootstrap' parameter. Doing so will trigger a redirect and the next page + // request will perform a full boostrap into the new environment, skipping + // install_system_rebuild(). + $install_state['parameters']['bootstrap'] = DRUPAL_BOOTSTRAP_VARIABLES; +} + +/** + * Install task: Performs a full bootstrap into the new environment. + */ +function install_system_rebuild(&$install_state) { + global $conf; + + // This phase is reached in the non-interactive installer only. + // We need to unset all overrides and rebuild all necessary facilities to get + // into a regular bootstrap state. + unset($conf['cache_classes']); + unset($conf['keyvalue_default']); + + // Ensure that custom service definitions in a prepared settings.php are + // applied. This effectively allows to install Drupal with custom Cache, + // KeyValue, and Lock backends in the non-interactive installer. + $conf_path = conf_path(); + if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) { + include DRUPAL_ROOT . '/' . $conf_path . '/settings.php'; + } + + $module_handler = drupal_container()->get('module_handler'); + // Reset module list and hook implementation statics. + $module_handler->setModuleList($module_filenames); + $module_handler->load($module); + module_load_install($module); + system_list_reset(); + $module_handler->resetImplementations(); + + // Bootstrap, but avoid session initialization. + // @see install_begin_request() + drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES); + _drupal_bootstrap_code(); + $kernel = new DrupalKernel('prod', TRUE, drupal_classloader(), FALSE); + $kernel->boot(); + + $install_state['base_system_verified'] = TRUE; +} + +/** * Installation task; install the base functionality Drupal needs to bootstrap. * * @param $install_state * An array of information about the current installation state. */ function install_base_system(&$install_state) { - // Install system.module. + // Install System module. + // This cannot use module_enable(), since System module's database tables have + // to be created separately in install_system_schema(), so we are able to + // switch to a full Drupal environment in install_system_rebuild(). drupal_install_system(); + // Something in the installer bootstrap primes file_get_stream_wrappers() too + // early. Resetting that static alone doesn't resolve it. + drupal_static_reset(); + // Call file_ensure_htaccess() to ensure that all of Drupal's standard // directories (e.g., the public files directory and config directory) have // appropriate .htaccess files. These directories will have already been @@ -904,7 +973,13 @@ function install_base_system(&$install_state) { $modules[] = drupal_get_profile(); state()->set('install_profile_modules', array_diff($modules, array('system'))); - $install_state['database_tables_exist'] = TRUE; + + // Now that the {users} table exists, the session can be initialized. + $install_state['parameters']['bootstrap'] = DRUPAL_BOOTSTRAP_CODE; + if ($install_state['interactive']) { + return; + } + drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); } /** @@ -915,16 +990,8 @@ function install_base_system(&$install_state) { * is already installed. */ function install_verify_completed_task() { - try { - if ($result = db_query("SELECT value FROM {variable} WHERE name = :name", array('name' => 'install_task'))) { - $task = unserialize($result->fetchField()); - } - } - // Do not trigger an error if the database query fails, since the database - // might not be set up yet. - catch (Exception $e) { - } - if (isset($task)) { + $task = state()->get('system.install_task'); + if ($task) { if ($task == 'done') { throw new Exception(install_already_done_error()); } @@ -1100,18 +1167,12 @@ function install_settings_form_submit($form, &$form_state) { ); drupal_rewrite_settings($settings); + $install_state['database_verified'] = TRUE; + $install_state['settings_verified'] = TRUE; // Add the config directories to settings.php. drupal_install_config_directories(); - - // Indicate that the settings file has been verified, and check the database - // for the last completed task, now that we have a valid connection. This - // last step is important since we want to trigger an error if the new - // database already has Drupal installed. - $install_state['settings_verified'] = TRUE; $install_state['config_verified'] = TRUE; - $install_state['database_verified'] = TRUE; - $install_state['completed_task'] = install_verify_completed_task(); } /** @@ -1605,22 +1666,6 @@ function install_load_profile(&$install_state) { } /** - * Performs a full bootstrap of Drupal during installation. - * - * @param $install_state - * An array of information about the current installation state. - */ -function install_bootstrap_full(&$install_state) { - // The early stages of the installer override the cache backend since Drupal - // isn't fully set up yet. Here the override is removed so that the standard - // cache backend will be used again. - unset($GLOBALS['conf']['cache_classes']['cache']); - drupal_static_reset('cache'); - - drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); -} - -/** * Installs required modules via a batch process. * * @param $install_state @@ -1630,6 +1675,12 @@ function install_bootstrap_full(&$install_state) { * The batch definition. */ function install_profile_modules(&$install_state) { + // Batch API relies on drupal_get_token() and thus an initialized session. + // Up until now, the entire installation process happened without a user. + // Now that we are in a full environment, we need to enforce the session to be + // regenerated, so we have a new session ID and it is stored for the user. + drupal_session_regenerate(); + $modules = state()->get('install_profile_modules') ?: array(); $files = system_rebuild_module_data(); state()->delete('install_profile_modules'); @@ -1776,15 +1827,6 @@ function install_configure_form($form, &$form_state, &$install_state) { // work during installation. drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))), 'setting'); - // Cache a fully-built schema. This is necessary for any invocation of - // index.php because: (1) setting cache table entries requires schema - // information, (2) that occurs during bootstrap before any module are - // loaded, so (3) if there is no cached schema, drupal_get_schema() will - // try to generate one but with no loaded modules will return nothing. - // - // @todo Move this to the 'install_finished' task? - drupal_get_schema(NULL, TRUE); - // Return the form. return _install_configure_form($form, $form_state, $install_state); } @@ -2381,5 +2423,5 @@ function install_configure_form_submit($form, &$form_state) { user_login_finalize(); // Record when this install ran. - variable_set('install_time', $_SERVER['REQUEST_TIME']); + state()->set('system.install_time', $_SERVER['REQUEST_TIME']); } diff --git a/core/includes/install.inc b/core/includes/install.inc index e9d666f..0b4799b 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -395,42 +395,55 @@ function drupal_verify_profile($install_state) { } /** - * Installs the system module. + * Installs the System module. * - * Separated from the installation of other modules so core system - * functions can be made available while other modules are installed. + * This is identical to module_enable(), with two exceptions: + * - System module's database schema has been installed in + * install_system_schema() already, as it is required for booting a kernel + * with regular services. module_enable() installs a module's database schema + * without a failsafe "IF NOT EXISTS" SQL condition, so it would bail out with + * database query errors. + * - The module entry for System module in the system.module:enabled + * configuration can only be written after the default configuration of System + * module has been installed, since the default config overwrites any + * potentially pre-existing config files. + * + * Therefore, this function performs the installation parts of module_enable() + * and then calls into module_enable() to enable the module. + * + * @see install_base_system() + * @see install_system_schema() */ function drupal_install_system() { - // Create tables. - drupal_install_schema('system'); - // Immediately boot a kernel to have real services ready. - $kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE); - $kernel->boot(); - - $system_path = drupal_get_path('module', 'system'); - require_once DRUPAL_ROOT . '/' . $system_path . '/system.install'; - $system_versions = drupal_get_schema_versions('system'); - $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; - drupal_container() - ->get('keyvalue') - ->get('system.schema') - ->set('system', $system_version); - - // System module needs to be enabled and the system/module lists need to be - // reset first in order to allow config_install_default_config() to invoke - // config import callbacks. - // @todo Installation profiles may override the system.module config object. - config('system.module') - ->set('enabled.system', 0) - ->save(); + + // Ensure that system.install is loaded. + require_once DRUPAL_ROOT . '/core/modules/system/system.install'; + + $module = 'system'; + + // Mark the System database schema as installed to prevent module_enable() + // from attempting to install it. + $versions = drupal_get_schema_versions($module); + $version = $versions ? max($versions) : SCHEMA_INSTALLED; + if ($last_removed = module_invoke($module, 'update_last_removed')) { + $version = max($version, $last_removed); + } + drupal_set_installed_schema_version($module, $version); // Update the module list to include it. - drupal_container()->get('module_handler')->setModuleList(array('system' => $system_path . '/system.module')); + drupal_container()->get('module_handler')->setModuleList(array($module => $system_path . '/system.module')); drupal_container()->get('module_handler')->resetImplementations(); - config_install_default_config('module', 'system'); + // Install default configuration. + config_install_default_config('module', $module); + + // Allow the module to perform install tasks. + module_invoke($module, 'install'); + // Record the fact that it was installed. + watchdog('system', '%module module installed.', array('%module' => $module), WATCHDOG_INFO); - module_invoke('system', 'install'); + // Enable the module. + module_enable(array($module)); } /** diff --git a/core/includes/module.inc b/core/includes/module.inc index d99b39d..3534e3e 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -350,14 +350,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) { _system_update_bootstrap_status(); // Update the kernel to include it. - // This reboots the kernel to register the module's bundle and its - // services in the service container. The $module_filenames argument is - // taken over as %container.modules% parameter, which is passed to a fresh - // ModuleHandler instance upon first retrieval. - // @todo install_begin_request() creates a container without a kernel. - if ($kernel = drupal_container()->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) { - $kernel->updateModules($module_filenames, $module_filenames); - } + drupal_container()->get('kernel')->updateModules(module_list(), $module_filenames); // Refresh the schema to include it. drupal_get_schema(NULL, TRUE); diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index 3d43a8c..97a3e74 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -145,7 +145,7 @@ public function encode($data) { */ public function decode($raw) { $data = @unserialize($raw); - return is_array($data) ? $data : FALSE; + return is_array($data) ? $data : array(); } /** diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 6422e9d..6ca5a88 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -173,9 +173,10 @@ public function encode($data) { */ public function decode($raw) { $data = $this->getParser()->parse($raw); - // A simple string is valid YAML for any reason. + // A simple string is valid YAML for any reason. Also, a config file may + // exist but can be empty, in which case $data is NULL. if (!is_array($data)) { - return FALSE; + return array(); } return $data; } diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php index a2b3448..7a6f75b 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php @@ -39,14 +39,14 @@ function testCRUD() { $data = $this->storage->read($name); $this->assertIdentical($data, FALSE); - // Reading a name containing non-decodeable data returns FALSE. + // Reading a name containing non-decodeable data returns an array. $this->insert($name, ''); $data = $this->storage->read($name); - $this->assertIdentical($data, FALSE); + $this->assertIdentical($data, array()); $this->update($name, 'foo'); $data = $this->storage->read($name); - $this->assertIdentical($data, FALSE); + $this->assertIdentical($data, array()); $this->delete($name); diff --git a/core/modules/system/config/system.module.disabled.yml b/core/modules/system/config/system.module.disabled.yml new file mode 100644 index 0000000..e69de29 diff --git a/core/modules/system/config/system.module.yml b/core/modules/system/config/system.module.yml index 696bedc..01151d1 100644 --- a/core/modules/system/config/system.module.yml +++ b/core/modules/system/config/system.module.yml @@ -1,2 +1 @@ -enabled: - system: '0' +enabled: { } diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/StateSystemUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/StateSystemUpgradePathTest.php index 4fb1f68..47cd712 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/StateSystemUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/StateSystemUpgradePathTest.php @@ -35,6 +35,14 @@ public function testSystemVariableUpgrade() { $expected_state = array(); + $expected_state['system.install_time'] = array( + 'value' => 1304208000, + 'variable_name' => 'install_time', + ); + $expected_state['system.install_task'] = array( + 'value' => 'done', + 'variable_name' => 'install_task', + ); $expected_state['node.node_access_needs_rebuild'] = array( 'value' => TRUE, 'variable_name' => 'node_access_needs_rebuild', diff --git a/core/modules/system/system.install b/core/modules/system/system.install index cfc9a4e..33326db 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -274,7 +274,7 @@ function system_requirements($phase) { // Determine when cron last ran. $cron_last = state()->get('system.cron_last'); if (!is_numeric($cron_last)) { - $cron_last = variable_get('install_time', 0); + $cron_last = state()->get('system.install_time') ?: 0; } // Determine severity based on time since cron last ran. @@ -1781,6 +1781,18 @@ function system_update_8025() { } /** + * Migrates install_task and install_time variables to State API. + * + * @ingroup config_upgrade + */ +function system_update_8026() { + update_variables_to_state(array( + 'install_task' => 'system.install_task', + 'install_time' => 'system.install_time', + )); +} + +/** * Cleans up javascript_parsed variable. * * @ingroup system_upgrade diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 5f540a3..1c07628 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -3723,7 +3723,7 @@ function system_run_automated_cron() { // If the site is not fully installed, suppress the automated cron run. // Otherwise it could be triggered prematurely by Ajax requests during // installation. - if (($threshold = config('system.cron')->get('threshold.autorun')) > 0 && variable_get('install_task') == 'done') { + if (($threshold = config('system.cron')->get('threshold.autorun')) > 0 && state()->get('system.install_task') == 'done') { $cron_last = state()->get('system.cron_last') ?: NULL; if (!isset($cron_last) || (REQUEST_TIME - $cron_last > $threshold)) { drupal_cron_run(); diff --git a/core/modules/system/tests/upgrade/drupal-7.state.system.database.php b/core/modules/system/tests/upgrade/drupal-7.state.system.database.php index a6f47ef..1c40289 100644 --- a/core/modules/system/tests/upgrade/drupal-7.state.system.database.php +++ b/core/modules/system/tests/upgrade/drupal-7.state.system.database.php @@ -12,6 +12,9 @@ // Update system settings to known values. db_merge('variable') + ->key(array('name' => 'install_time'))->fields(array('value' => serialize(1304208000))) + ->execute(); +db_merge('variable') ->key(array('name' => 'node_cron_views_scale')) ->fields(array('value' => serialize(1.0 / 2000))) ->execute();