Change record status: 
Project: 
Introduced in branch: 
8.0.x
Description: 

This is a Drupal 8.0.x to 8.0.x change record

ConfigFactoryInterface::get() no longer returns configuration objects that can be saved. This is to ensure that configuration overrides do not get into active configuration. Configuration overrides are, for example, global overrides set in settings.php or translations provided by the locale module. If you need to get a configuration object that can be saved, use ConfigFactoryInterface::getEditable(). Objects returned by that method will not have overrides applied.

Previously

// Just get the site name (with overrides).
$site_name = \Drupal::config('system.site')->get('name');

// Set the site name.
\Drupal::config('system.site')->set('name', 'My fantastic site')->save();

Now

// Just get the site name (with overrides, same as before).
$site_name = \Drupal::config('system.site')->get('name');

// Set the site name.
\Drupal::configFactory()->getEditable('system.site')->set('name', 'My fantastic site')->save();

Do make sure that data taken from \Drupal::config() is not fed back to a getEditable()->set() sequence, or you get overrides bleeding into your active configuration. That could result in development API key credentials or testing email addresses being saved into your configuration to be deployed. Other side effects of bad API use may include translations or domain specific settings overwriting your original configuration. Forms have infrastructure to help with getting and saving editable configuration consistently, see below. For other uses you need to ensure to mirror getting and setting configuration both from/to editable configuration.

Forms that save configuration

Forms that save configuration need to declare the configuration objects they want to save. Forms that extend Drupal\Core\Form\ConfigFormBase need to implement Drupal\Core\Form\ConfigFormBaseTrait::getEditableConfigNames(). This way using $this->config($name) will return editable configuration objects for the provided names. For other names, $this->config($name) will now return immutable configuration. If a form does not extend the base class it can just implement ConfigFormBaseTrait to get the same functionality.

For example:

/**
 * Provides the site configuration form.
 */
class SiteConfigureForm extends ConfigFormBase {

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'system.date',
      'system.site',
      'update.settings',
    ];
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('system.date');

// ... the rest of the implemtation

This allows the form to interact with saveable and override-free configuration objects for the system.date, system.site and update.settings configuration.

Altering forms that save configuration

When altering configuration forms, you should make sure to get values and save values with editable configuration as well.

Before:

// ...
function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['admin_theme']['use_admin_theme'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use the administration theme when editing or creating content'),
    '#default_value' => \Drupal::config('node.settings')->get('use_admin_theme'),
  );
  $form['#submit'][] = 'node_form_system_themes_admin_form_submit';
}

// ...
function node_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
  \Drupal::config('node.settings')
    ->set('use_admin_theme', $form_state->getValue('use_admin_theme'))
    ->save();
  .. 
}

After:

// ...
function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['admin_theme']['use_admin_theme'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use the administration theme when editing or creating content'),
    '#default_value' => \Drupal::configFactory()->getEditable('node.settings')->get('use_admin_theme'),
  );
  $form['#submit'][] = 'node_form_system_themes_admin_form_submit';
}

// ...
function node_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
  \Drupal::configFactory()->getEditable('node.settings')
    ->set('use_admin_theme', $form_state->getValue('use_admin_theme'))
    ->save();
  .. 
}

If you would use regular \Drupal::config()->set(), you would immediately receive a Drupal\Core\Config\ImmutableConfigException. If you are to use \Drupal::configFactory()->getEditable() on the submit function but not in the form generator, you are to possibly bleed overrides into your active configuration and global settings may change unexpectedly. Use \Drupal::configFactory()->getEditable() in both the default value lookup and the save callback.

Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done

Comments

sidharrell’s picture

I updated https://www.drupal.org/node/2206607
Don't know if there are other places that need updating, as well.

Sidney Harrell

ifux’s picture

-

wizonesolutions’s picture

Support my open-source work: Patreon | Ko-Fi | FillPDF Service