Community Documentation

How to upgrade variables into configuration

Last updated November 5, 2012. Created by sun on July 2, 2012.
Edited by znerol, miro_dietiker, penyaskito, barraponto. Log in to edit this page.

In Drupal 7 and before one of the common ways of storing settings was using variable_get() and variable_set(). In Drupal 8 these have been replaced with the new configuration system API/storage.

Short introduction to CMI

  • Modules store default settings in configuration files that are stored in a config/ folder in the module root directory.
  • When a module is enabled these default settings are copied to a 'config' folder inside sites/default/files. This folder has a unique suffix for security reasons (eg. config_dWrEJUolcldeMHORCNbISC_GcGNM_cVAm7s9fVtru-E)
  • When settings are changed by a site administrator these are stored both in the database (in the cache_config table) and in the config files.

Upgrade procedure

  1. Decide on a config object name and a name for the settings. Simple settings can be stored in a config object named <module_name>.settings, while for more complex settings it is advisable to use sub-keys. See the guidelines below.
  2. Create a folder named config in your module's root directory.
  3. Create the default settings file and put the default configuration in. The filename convention is <module_name>.<config_object_name>.<optional_sub_key>.yml. For example, this is the config file for the 'large' image style from the Image module (image.style.large.yml):

    name: large
    label: Large (480x480)
    effects:
      ddd73aa7-4bd6-4c85-b600-bdf2b1628d1d:
        name: image_scale
        data:
          width: '480'
          height: '480'
          upscale: '1'
        weight: '0'
        ieid: ddd73aa7-4bd6-4c85-b600-bdf2b1628d1d
  4. Grep the entire code base and replace all instances of variable_get() and variable_set() with config()->get() and config()->set(). An example:

    <?php
      $items_per_page
    = config('node.settings')->get('items_per_page');
    ?>

    <?php
     
    function node_form_system_site_information_settings_form_submit($form, &$form_state) {
       
    config('node.settings')
          ->
    set('items_per_page', $form_state['values']['default_nodes_main'])
          ->
    save();
      }
    ?>
  5. Create an update hook that updates the variables to CMI with update_variables_to_config(). Example:

    <?php
    /**
    * Converts default_nodes_main variable to config.
    *
    * @ingroup config_upgrade
    */
    function node_update_8009() {
     
    update_variables_to_config('node.settings', array(
       
    // 'old_variable' => 'new_config.sub_key'
       
    'default_nodes_main' => 'items_per_page'
     
    ));
    }
    ?>

Guidelines

  1. Within your conversion issue work, convert one variable at a time.
    • Determine the variable name to convert.
    • Grep the entire Drupal code base for the variable name and identify all instances that need to be updated.
    • Speed up greps by checking /core first. But do not forget to grep /profiles.
  2. New configuration objects are only picked up when a module is first enabled. If you add new configuration to a module that is already enabled, you should disable, uninstall and reenable the module for the configuration files to appear.
  3. Keep configuration object names short and concise.
    • If a module has only one set of settings (i.e., one settings form that will result in one configuration object), then the standard configuration object name is $module.settings.

      The following bullets only apply to modules that need multiple configuration objects, in which case "settings" would be ambiguous:

    • Given a module settings form system_site_information_settings_form() that manages the variables:
      site_name
      site_mail
      site_frontpage
      site_403
      ...
    • Understand that the primary namespace/owner of the configuration object is System module, so the configuration object name has to start with system..
    • Do not convert the form constructor function's name as-is for the configuration object name (system.site-information). No Drupal developer wants to have to remember or deal with needlessly long names on a daily basis.
    • Instead, find the common denominator and shortest base name of all variables (site) and choose an appropriate configuration object name:
      system.site
  4. Strip the configuration object name (or parts of it) from key names.
    • Given a new configuration object name:
      system.site

      and a variable name:
      site_name
    • Understand that converting site_name into system.site:site_name is bad DX. ;)
    • Instead, remove the duplicate site_ from the key name; i.e.:
      system.site:name
  5. Leverage sub-keys.
    • Determine and understand the meaning of the entire set of variables to be converted.
    • Given a subset of variables:
      site_frontpage
      site_403
      site_404
    • Research a bit to understand that all of them refer to internal router paths that denote pages to be shown in certain cases.
    • Do not convert them to meaningless frontpage, 403, 404.
    • Instead, leverage sub-keys and introduce DX sanity for D8 developers:
      page.front
      page.403
      page.404
  6. Direct access, or provide context.
    • config('system.site')->get('name') is fine when being invoked only once within a function.
    • It's also fine, if the respective code is only reached through certain code conditions.
    • However, when config('system.site') is unconditionally used multiple times within a function, then only invoke it once.
    • Unless the context is crystal clear, try to avoid the ambiguous variable name $config.
    • Instead, use a self-descriptive variable name; e.g.:
      $site_config = config('system.site');
  7. Use system_config_form().
    • For a simple settings form somemodule_form(), write a form submission handler to save the configuration; e.g., somemodule_form_submit().
    • End the form with:
        return system_config_form($form, $form_state);

      This retains a consistent form actions container and submit button on settings forms. It also adds a handler for outputting a consistent (positive) confirmation message after form submission. However, it does NOT save any configuration like system_settings_form() did before. somemodule_form_submit() is responsible for that.
    • This takes effect until #1324618: Implement automated config saving for simple settings forms is resolved.

Upgrade path tests

  1. Prefill your database:
    core/modules/system/tests/upgrade/drupal-7.system.database.php
    <?php
    ..
    // Add non-default system settings.
    db_insert('variable')->fields(array(
     
    'name',
     
    'value',
    ))
    ..
    ->
    values(array(
     
    'name' => 'node_rank_promote',
     
    'value' => 'i:10;',
      ))
    ->
    values(array(
     
    'name' => 'node_rank_custom_from_contrib',
     
    'value' => 'i:5;',
    ))
    ..
    ->
    execute();
    ..
    ?>
  2. Preload the database values and check for expected values, example:
    core/modules/system/lib/Drupal/system/Tests/Upgrade/SystemUpgradePathTest.php
    <?php
    class SystemUpgradePathTest extends UpgradePathTestBase {
    ..
      public function
    setUp() {
       
    $this->databaseDumpFiles = array(
         
    drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz',
         
    drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.system.database.php',
        );
       
    parent::setUp();
      }
    ..
      public function
    testVariableUpgrade() {
    ..
       
    $expected_config['node.settings'] = array(
         
    'search_rank.promote' => 10,
         
    'search_rank.custom_from_contrib' => 5,
        );
    ..
        foreach (
    $expected_config as $file => $values) {
         
    $config = config($file);
         
    $this->verbose(print_r($config->get(), TRUE));
          foreach (
    $values as $name => $value) {
           
    $stored = $config->get($name);
           
    $this->assertEqual($value, $stored, format_string('Expected value for %name found: %stored (previously: %value).', array('%stored' => $stored, '%name' => $name, '%value' => $value)));
          }
        }
    ?>

More information