function update_prepare_d8_bootstrap

Performs extra steps required to bootstrap when using a Drupal 7 database.

Users who still have a Drupal 7 database (and are in the process of updating to Drupal 8) need extra help before a full bootstrap can be achieved. This function does the necessary preliminary work that allows the bootstrap to be successful.

No access check has been performed when this function is called, so no irreversible changes to the database are made here.

1 call to update_prepare_d8_bootstrap()
update.php in drupal/core/update.php
Administrative page for handling updates from one Drupal version to another.

File

drupal/core/includes/update.inc, line 90
Drupal database update API.

Code

function update_prepare_d8_bootstrap() {
  include_once DRUPAL_ROOT . '/core/includes/install.inc';
  include_once DRUPAL_ROOT . '/core/includes/schema.inc';

  // Bootstrap to configuration.
  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);

  // Check whether settings.php needs to be rewritten.
  $settings_exist = !empty($GLOBALS['config_directories']);

  // If any of the required settings needs to be written, then settings.php
  // needs to be writable.
  if (!$settings_exist) {
    $settings_file = conf_path() . '/settings.php';
    $writable = drupal_verify_install_file($settings_file, FILE_EXIST | FILE_READABLE | FILE_WRITABLE);
    $requirements['settings file']['title'] = 'Settings file';
    if ($writable) {
      $requirements['settings file'] += array(
        'value' => 'settings.php is writable.',
      );
    }
    else {
      $requirements['settings file'] += array(
        'value' => 'settings.php is not writable.',
        'severity' => REQUIREMENT_ERROR,
        'description' => 'Drupal requires write permissions to <em>' . $settings_file . '</em> during the update process. If you are unsure how to grant file permissions, consult the <a href="http://drupal.org/server-permissions">online handbook</a>.',
      );
    }
    update_extra_requirements($requirements);
  }
  if (!$settings_exist || !is_dir(config_get_config_directory('active')) || !is_dir(config_get_config_directory('staging'))) {

    // @todo Race-condition: drupal_install_config_directories() calls into
    //   install_ensure_config_directory(), which calls into
    //   file_prepare_directory(), whichs calls into file_get_stream_wrappers(),
    //   which attempts to invoke hooks with a non-existing module/hook system.
    include_once DRUPAL_ROOT . '/core/includes/module.inc';
    include_once DRUPAL_ROOT . '/core/includes/cache.inc';
    $module_list['system']['filename'] = 'core/modules/system/system.module';
    module_list(NULL, $module_list);
    require_once DRUPAL_ROOT . '/' . $module_list['system']['filename'];

    // Ensure the configuration directories exist and are writable, or create
    // them. If the directories have not been specified in settings.php and
    // created manually already, and either directory cannot be created by the
    // web server, an exception will be thrown, halting the update.
    drupal_install_config_directories();
  }

  // Bootstrap the database.
  drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);

  // If the site has not updated to Drupal 8 yet, check to make sure that it is
  // running an up-to-date version of Drupal 7 before proceeding. Note this has
  // to happen AFTER the database bootstraps because of
  // drupal_get_installed_schema_version().
  try {
    $system_schema = drupal_get_installed_schema_version('system');
  } catch (\Exception $e) {
    $system_schema = db_query('SELECT schema_version FROM {system} WHERE name = :system', array(
      ':system' => 'system',
    ))
      ->fetchField();
  }
  if ($system_schema < 8000) {
    $has_required_schema = $system_schema >= REQUIRED_D7_SCHEMA_VERSION;
    $requirements = array(
      'drupal 7 version' => array(
        'title' => 'Drupal 7 version',
        'value' => $has_required_schema ? 'You are running a current version of Drupal 7.' : 'You are not running a current version of Drupal 7',
        'severity' => $has_required_schema ? NULL : REQUIREMENT_ERROR,
        'description' => $has_required_schema ? '' : 'Please update your Drupal 7 installation to the most recent version before attempting to upgrade to Drupal 8',
      ),
    );
    update_extra_requirements($requirements);

    // @todo update.php stages seem to be completely screwed up; the initial
    //   requirements check is not supposed to change the system. All of the
    //   following code seems to have been mistakenly/unknowingly added here and
    //   does not belong into update_prepare_d8_bootstrap().
    if ($has_required_schema) {
      if (!db_table_exists('key_value')) {
        $specs = array(
          'description' => 'Generic key-value storage table. See state() for an example.',
          'fields' => array(
            'collection' => array(
              'description' => 'A named collection of key and value pairs.',
              'type' => 'varchar',
              'length' => 128,
              'not null' => TRUE,
              'default' => '',
            ),
            'name' => array(
              'description' => 'The key of the key-value pair. As KEY is a SQL reserved keyword, name was chosen instead.',
              'type' => 'varchar',
              'length' => 128,
              'not null' => TRUE,
              'default' => '',
            ),
            'value' => array(
              'description' => 'The value.',
              'type' => 'blob',
              'not null' => TRUE,
              'size' => 'big',
              'translatable' => TRUE,
            ),
          ),
          'primary key' => array(
            'collection',
            'name',
          ),
        );
        db_create_table('key_value', $specs);
      }

      // Bootstrap variables so we can update theme while preparing the update
      // process.
      drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);

      // Update the 'language_default' system variable, if configured.
      // Required to run before drupal_install_config_directories(), since that
      // triggers a call into system_stream_wrappers(), which calls t(), which
      // calls into language_default().
      $language_default = variable_get('language_default');
      if (!empty($language_default) && (isset($language_default->langcode) || isset($language_default->language))) {
        if (!isset($language_default->langcode)) {
          $language_default->langcode = $language_default->language;
        }
        unset($language_default->language);

        // In D8, the 'language_default' is not anymore an object, but an array,
        // so make sure that the new value that is saved into this variable is an
        // array.
        variable_set('language_default', (array) $language_default);
      }
      $module_config = config('system.module');
      $disabled_modules = config('system.module.disabled');
      $theme_config = config('system.theme');
      $disabled_themes = config('system.theme.disabled');
      $schema_store = drupal_container()
        ->get('keyvalue')
        ->get('system.schema');

      // Load system.module, because update_prepare_d8_bootstrap() is called in
      // the initial minimal update.php bootstrap that performs the core
      // requirements check.
      require_once DRUPAL_ROOT . '/core/modules/system/system.module';

      // Make sure that the bootstrap cache is cleared as that might contain
      // incompatible data structures.
      cache('bootstrap')
        ->deleteAll();

      // Retrieve all installed extensions from the {system} table.
      // Uninstalled extensions are ignored and not converted.
      $result = db_query('SELECT name, status, weight, schema_version, type FROM {system} WHERE type = :theme OR (type = :module AND schema_version <> :schema_uninstalled)', array(
        ':theme' => 'theme',
        ':module' => 'module',
        ':schema_uninstalled' => SCHEMA_UNINSTALLED,
      ));

      // Populate a fixed module list (again, why did it get lost?) to avoid
      // errors due to the drupal_alter() in _system_rebuild_module_data().
      $module_list['system']['filename'] = 'core/modules/system/system.module';
      module_list(NULL, $module_list);
      $module_data = _system_rebuild_module_data();

      // Migrate each extension into configuration, varying by the extension's
      // status, and record its schema version.
      foreach ($result as $record) {
        if ($record->type == 'module') {
          if ($record->status && isset($module_data[$record->name])) {
            $module_config
              ->set('enabled.' . $record->name, $record->weight);
          }
          else {
            $disabled_modules
              ->set($record->name, $record->weight);
          }
        }
        elseif ($record->type == 'theme') {
          if ($record->status) {
            $theme_config
              ->set('enabled.' . $record->name, 0);
          }
          else {
            $disabled_themes
              ->set($record->name, 0);
          }
        }
        $schema_store
          ->set($record->name, $record->schema_version);
      }
      $module_config
        ->set('enabled', module_config_sort($module_config
        ->get('enabled')))
        ->save();
      $disabled_modules
        ->save();
      $theme_config
        ->save();
      $disabled_themes
        ->save();

      // Update the dynamic include paths that might be used before running the
      // proper update functions.
      update_prepare_stored_includes();

      // Update the environment for the language bootstrap if needed.
      update_prepare_d8_language();

      // Prime the classloader.
      system_list('module_enabled');

      // Change language column to langcode in url_alias.
      if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) {
        db_drop_index('url_alias', 'alias_language_pid');
        db_drop_index('url_alias', 'source_language_pid');
        $langcode_spec = array(
          'description' => "The language code this alias is for; if 'und', the alias will be used for unknown languages. Each Drupal path can have an alias for each supported language.",
          'type' => 'varchar',
          'length' => 12,
          'not null' => TRUE,
          'default' => '',
        );
        $langcode_indexes = array(
          'indexes' => array(
            'alias_langcode_pid' => array(
              'alias',
              'langcode',
              'pid',
            ),
            'source_langcode_pid' => array(
              'source',
              'langcode',
              'pid',
            ),
          ),
        );
        db_change_field('url_alias', 'language', 'langcode', $langcode_spec, $langcode_indexes);
      }
    }
  }
}