1

I have a custom module where I need to have a couple different types of configuration, both immutable and mutable. The immutable portion contains a feed URL for a couple different sites, so I have /my_module/config/install/my_module.settings.yml set up like this:

sites:
  site1:
    channel_url: 'http://www.site1.org/feed/channels'
  site2:
    channel_url: 'http://www.site2.com/feed/channels'
list_time: 24

That works fine, and I can read from it via $config-get();.

The second part of my settings involves mapping of tids between the two sites (used for importing video nodes from one site to another. My initial thought was to modify the settings like so:

sites:
  site1:
    channel_url: 'http://www.site1.org/feed/channels'
    mappings:
      1: 1
      2: 2
      3: 3
  site2:
    channel_url: 'http://www.site2.com/feed/channels'
    mappings:
      7: 7
      8: 8
      9: 9
list_time: 24

However, since this is mutable, it appears that this isn't allowed (based on the error messages I get when I try to run $config->set().

From what I'm finding, it looks like I need to have a separate schema config file for my mapping data. I'm still wading through docs, but if someone could verify if I'm correct in my thinking and maybe provide a sample of what my schema should look like, I'd appreciate it.

UPDATE: Reading through this change record, it appears that I can write to my settings file if I declare it in my form class in getEditableConfigNames(), which I've done:

protected function getEditableConfigNames() {
  return ['my_module.settings'];
}

It also appears that, according to the error message I get, I need to retrieve it with \Drupal\Core\Config\ConfigFactoryInterface::getEditable()

Drupal\Core\Config\ImmutableConfigException: Can not set values on immutable configuration my_module.settings:sites. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object in Drupal\Core\Config\ImmutableConfig->set() (line 27 of core/lib/Drupal/Core/Config/ImmutableConfig.php).

Just keep swimming....

UPDATE2: Base on @berdir's comment below, I'm showing what I have, since in my original question, I didn't state that I am already using the ConfigFormBase class:

class MyModuleAdminForm extends ConfigFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'my_module_settings';
  }

  /**
   * {@inheritdoc}
   */
  public function buildform(array $form, FormStateInterface $form_state) {
    $form = array();
    $channels = array();

    // build form here

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}.
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

  }

  protected function getEditableConfigNames() {
    return ['my_module.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $config = $this->config('my_module:settings');

    foreach($values as $site => $mappings) {
      if (is_array($mappings)) {
        foreach ($mappings as $source_channel => $target_channel) {
          $config->set('sites',[$site => ['mappings' => [$source_channel => $target_channel]]]);
        }
      }
    }
     $config->save();

    parent::submitForm($form, $form_state);
  }
}

However, this still gives me the same error. Am I using $this->config() incorrectly? Or do I still need to use getEditable() somewhere?

3 Answers 3

2

Mutable or Immutable has nothing to do with config schema, that's something else.

getEditableConfigNames() only works if you actually implement \Drupal\Core\Form\ConfigFormBase and $this->config().

Otherwise you need to explicitly get the config.factory service or \Drupal::configFactory() and then call getEditable() on that, instead of get().

1
  • I updated my original question with more details.
    – wonder95
    Commented Apr 6, 2017 at 18:15
0

I got past this error with the code I had above after figuring out one tiny issue. The code in ConfigFormBaseTrait::config() (called with $this->config() in a form that uses ConfigFormBase) has the following code:

if (in_array($name, $this->getEditableConfigNames())) {
  // Get a mutable object from the factory.
  $config = $config_factory->getEditable($name);
}
else {
  $config = $config_factory->get($name);
}

For some reason in_array() was returning FALSE, even though I had my_module.settings returned from getEditableConfigNames(). The eagle eyed will note that in my last update in the original question I had

$this->config('my_module:settings');

but in getEditableConfigNames() I had

return ['my_module.settings'];

The difference was the period vs the colon in the config value. Sigh.

With that change, config() loads getEditable() instead of get(), and I'm off and running.

0

when it's immunable you should use configFactory.
for example:

$alertConfig = \Drupal::configFactory()
  ->getEditable('sitewide_alert.settings');

$alertConfig->set('alert_styles', "test|TestValue")->save();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.