Simple Configuration API
The configuration API provides a central place for modules to store configuration data.
This data can be simple configuration like your site name, or more complex information managed with configuration entities, such as views and content types.
Configuration is a place to store information that you would want to synchronize from development to production.
This information is often created during site-building and is not typically generated by regular users during normal site operation.
You should use the State API, not configuration, for storing local variables that shouldn't travel between instances.
Use state for hidden system values if you never want to deploy it between environments.
You can reset a system, losing all states. Its configuration remains.
The configuration API comes in two flavors - the (simple) Config API and the Configuration Entity API.
The key difference is that the Config API is the singleton use case.
A singleton is where there can be only a single instance of this configuration.
A good example would be the site's name.
The Configuration Entity API should store multiple configuration sets - for example, node types, views, vocabularies, and fields.
Each module can provide a default configuration.
For example, the maintenance mode settings are defined in core/modules/system/config/install/system.maintenance.yml
.
In this file, the first part is a namespace representing which module supplied this configuration (system module in this example), followed by the sub-system (maintenance in this example).
The file must be under a config/install directory.
It must contain the symbol '.' in the file name for validation in ConfigBase->validateName($name)
.
This file contains the following YAML:
message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.'
langcode: en
Configuration can also be nested, as in the performance settings (system.performance.yml
):
cache:
page:
enabled: '0'
max_age: '0'
preprocess:
css: '0'
js: '0'
response:
gzip: '0'
The data at the root of a configuration must be represented as a mapping and not an unpredictable sequence.
For example, if you are storing data for each available entity type, make the parent key the entity type and add a root key of entity_type
.
See the example layout below:
entity_type:
commerce_order:
foo: 'bar'
node:
foo: 'bar'
user:
foo: 'bar'
If the entity types are the root key then it is impossible to represent the configuration using schema.
Additionally Drupal core would be unable to add extra information when the configuration is installed as part of a module (or theme) installation.
The Config object
You interact with these files through the Config object, and you instantiate a Config object by calling the function config()
with the filename minus the extension.
Calling the config function will return an instance of \Drupal\Core\Config\ImmutableConfig.
// Immutable Config (Read Only).
$config = \Drupal::config('system.performance');
// Mutable Config (Read / Write).
$config = \Drupal::service('config.factory')->getEditable('system.performance');
Once you have a Config object, you can interact with it in various ways.
Configuration is read using the get()
method.
This can be used in several ways. To read a piece of configuration, just provide its key.
$config = \Drupal::config('system.maintenance');
$message = $config->get('message');
Calls to \Drupal::config()
can also be chained.
$message = \Drupal::config('system.maintenance')->get('message');
To read nested configuration, separate the keys with the '.' character.
$enabled = \Drupal::config('system.performance')->get('cache.page.enabled');
You can read the configuration at any level, if there is a configuration nested underneath your level, it will be returned as an array.
$page_cache = \Drupal::config('system.performance')->get('cache.page');
This would return an array with two keys - 'enabled' and 'max_age'.
To return all the data in a config object, just call get()
with no arguments.
Also, you can return all configuration keys available on the system or just those keys starting with a particular substring ($prefix).
$keys = \Drupal::service('config.factory')->listAll($prefix = "");
Config Factory
To change a configuration you will need to get an instance of \Drupal\Core\Config\Config (Mutable config object) by making a call to getEditable() on the config factory.
Attempting to make a change or calling a delete() / save() function on an instance of \Drupal\Core\Config\ImmutableConfig will throw an ImmutableConfigException.
This is done in the following way:
\Drupal::service('config.factory')->getEditable('system.performance');
Configuration is changed or added using the set()
method and saved using the save()
method.
Note that configuration must be explicitly saved; simply setting data into a configuration does not save it.
You save data into a config object the same way that you read it, by referencing the keys and saving appropriate data.
The syntax is the same as variable_set()
was in previous versions of Drupal.
$config = \Drupal::service('config.factory')->getEditable('system.performance');
// Set a scalar value.
$config->set('cache.page.enabled', 1);
// Set an array of values.
$page_cache_data = ['enabled' => 1, 'max_age' => 5];
$config->set('cache.page', $page_cache_data);
// Save your data to the database.
$config->save();
The set()
the function is also chainable, so if you only need to change one value, you can do it in a single line of code.
\Drupal::service('config.factory')->getEditable('system.performance')->set('cache.page.enabled', 1)->save();
If you want to replace all the data in the configuration object, use the setData()
function.
You cannot use setData()
to replace just a subset of the data - if you want to replace anything less than the entire object you must use one or more calls set()
instead.
When using setData()
you must specify every key and value in the same associative array format as is returned by get()
with no arguments.
For the system performance settings in system.performance.yml
, this would look like the following:
// Set all values.
\Drupal::service('config.factory')->getEditable('system.performance')->setData([
'cache' => [
'page' => [
'enabled' => '0',
'max_age' => '0',
],
],
'preprocess' => [
'css' => '0',
'js' => '0',
],
'response' => [
'gzip' => '0',
],
])
->save();
Removing configuration
Individual configuration values can be unset using the clear()
function, which is also chainable.
$config = \Drupal::service('config.factory')->getEditable('system.performance');
$config->clear('cache.page.max_age')->save();
$page_cache_data = $config->get('cache.page');
In this example $page_cache_data
would return an array with one key - 'enabled' - because 'max_age' was unset.
Whole configuration sets can be removed using the delete()
function.
\Drupal::service('config.factory')->getEditable('system.performance')->delete();
Note that this should not be followed by a call to save()
, as doing so would create an empty version of the configuration set.
Avoid instantiating config objects multiple times within the same function, as this is a performance drain.
The following code unnecessarily instantiates the config object 'foo.bar' twice.
\Drupal::service('config.factory')->getEditable('foo.bar')->set('foo', 'foo')->save();
\Drupal::service('config.factory')->getEditable('foo.bar')->set('bar', 'bar')->save();
A better solution would be to instantiate the config object once, save it into a variable, and work with that variable for the rest of your code scope.
$config = \Drupal::service('config.factory')->getEditable('foo.bar');
$config
->set('foo', 'foo')
->set('bar', 'bar')
->save();
Injecting configuration values into services
Configuration values can be injected into your custom service using service factory.
services:
app.service:
class: Drupal/mail_module/Service
factory: Drupal/mail_module/ServiceFactory:create
arguments: ['@config.factory']
class ServiceFactory {
static function create($config) {
return new Service($config->get('mail.config')->get('transport'));
}
}
class Service {
public function __construct($transport) {
$this->mailTransport = $transport;
}
}
You can use a factory for your app.mailer
service.
The factory take cares of retrieving the configuration for the service.
The service can stay decoupled from the configuration service and does not need to know how the config parameters are named.
services:
app.mailer:
class: Drupal/mail_module/Mailer
factory: Drupal/mail_module/MailerFactory:create
arguments: ['@config.factory']
class MailerFactory {
static function create($config) {
return new Mailer($config->get('mail.config')->get('transport'));
}
}
class Mailer {
public function __construct($transport) {
$this->mailTransport = $transport;
}
}
Configuration can change at runtime, the service definition is usually persisted, and rebuilding it is expensive.
Assuming it is the configuration that you want users to change.
If it is not, then you can use parameters, just like the Symfony example. Then you can put your configuration in services.yml in sites/default. But you can only change it by changing the code and rebuilding the container.
read more from the Symfony documentation: How to Configure a Service with a Configurator