Step 5: How to upgrade D7 variables to D8's state system

Last updated on
15 October 2016

Old-style Drupal Variables (formerly controlled with variable_set and variable_get) need to be converted to Drupal 8's new configuration system API/storage.

See also: Converting 7.x modules to 8.x, Upgrading 7.x themes to 8.x for further required changes to contrib code in order to work with Drupal 8. The conversion approach below is essential to getting D7 code to work in D8, since variable_set and variable_get will throw fatal errors.

Configuration settings that are edited by end users or implemented across multiple instances should be set with Config API, not State API. See Upgrading Drupal 7 Variables to Drupal 8 Configuration.

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.
  2. Keep state identifiers short and concise. Generally these can probably stay the same as they were in Drupal 7, unless the old name was incorrect or confusing in some way.
  3. The state system is initialized by calling the Drupal::state() function. Interact with the state system using the get(), set() and delete() functions. The Drupal::state() function returns a state object, so you can do $data = \Drupal::state()->get('my_state_data');
  4. When retrieving data, the state system does not provide a way to provide a default the way the old variable system did. However, you can provide a default when it returns FALSE, indicating that there is no data. A concise way to do this is $state = \Drupal::state()->get('my_state') ?: 'Nothing there';

    Note: If the boolean value of FALSE or the integer 0 are valid data for your state variable, then this will require special handling.

  5. Here is a simple example of converting variables to state:

    Drupal 7

      variable_set('my_data', 'foo');
      $data = variable_get('my_data', 'bar');
      variable_del('my_data');
    

    Drupal 8

      \Drupal::state()->set('my_data', 'foo');
      $data = \Drupal::state()->get('my_data') ?: 'bar';
      \Drupal::state()->delete('my_data');
    
  6. The variable name should be changed so that we can identify the module that creates it. The key should use the same namespace strategy as the configuration system. So for example:
    • cron_last becomes system.cron_last
    • node_cron_last becomes node.cron_last
    • menu_masks becomes routing.menu_masks.router
  7. If the value needs to be maintained through the Drupal 7 to 8 upgrade it should be migrated using the migration API. However if a variable should be migrated it is probably not state.
  8. Delete states on uninstall:
    /core/modules/comment/comment.install
    function comment_uninstall() {
    ...
      // Remove states.
      \Drupal::state()->delete('comment.node_comment_statistics_scale');
     }
     
    
  9. Add test coverage to the upgrade tests:
    Prefill values for an upgrade test
    /core/modules/system/tests/upgrade/drupal-7.state.system.database.php
    db_merge('variable')
      ->key(array('name' => 'node_cron_comments_scale'))
      ->fields(array('value' => serialize(1.0 / 1000)))
      ->execute();
    

    Check if new values apply
    /core/modules/system/lib/Drupal/system/Tests/Upgrade/StateSystemUpgradePathTest.php

        $expected_state['comment.count_scale'] = array(
          'value' => 1.0 / 1000,
          'variable_name' => 'node_cron_comments_scale',
        );