Not every form needs a database table behind it. A single site-wide setting — an API key, a toggle, a default value — doesn't need its own entity type or schema; it just needs a place to live that survives between page loads. That place is Drupal's configuration system, and config.factory is the service that reads and writes it.
What you'll learn in this lesson
- How to get an editable configuration object inside
submitForm() - How to set values on it and persist them
- Why
getEditable()exists as a separate call from the read-onlyget()
Writing a value to config
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->configFactory()->getEditable('my_module.settings')
->set('greeting', $form_state->getValue('greeting'))
->save();
parent::submitForm($form, $form_state);
}
getEditable('my_module.settings') loads (or creates) the configuration object named my_module.settings — matching the filename it'll live in as YAML, my_module.settings.yml. set() stages a value under a key, and save() actually persists it to the active configuration storage. Chaining set() calls before one final save() is the normal pattern when writing several values at once.
Why getEditable(), not just get()
Drupal deliberately makes you ask for an editable config object before you're allowed to write to it. configFactory()->get('my_module.settings') (no "Editable") returns an immutable object — calling ->set() on it throws an exception. This isn't an accident: it stops code that only meant to read a setting from accidentally mutating shared configuration as a side effect.
ConfigFormBase (rather than plain FormBase), you get $this->config('my_module.settings') as a shortcut that already returns an editable object for names listed in your form's getEditableConfigNames() method — slightly less code than calling configFactory()->getEditable() directly.Quick check: you call
$this->configFactory()->get('my_module.settings')->set('greeting', 'Hi')->save();— what happens? A runtime exception —get()returns an immutable config object, and callingset()on it is not allowed. You'd needgetEditable()instead.
Key takeaways
- Configuration is the right storage choice for small, site-wide settings that don't need their own entity type.
configFactory()->getEditable('name')->set('key', $value)->save()is the standard write pattern.get()returns an immutable object for reading; onlygetEditable()allowsset().- Extending
ConfigFormBasegives you a shorthand$this->config()method for names already declared ingetEditableConfigNames().
Coming up next
Configuration is great for settings, but most forms exist to create or update actual content. The next lesson covers the entity-backed side of form submission — creating and updating entities directly from a form.