Loading config programmatically
In Drupal 8, there are many ways to interact with configuration from PHP. Most will allow you to write the config values, but some are read-only. Some will include 'overrides' from settings.php, or translations. There are many layers of abstraction, that each have different purposes, so it can be easy to run into subtle unintended problems (or more obvious errors!) if you pick a method that doesn't quite suit what you actually need to do. Here I'm going to outline some of them and when you might pick each one.
For almost all of these suggestions, you can call the
->get($sub_value) method on them to get specific sub-values out of the returned object/data. Also, wherever I have written
$config_factory, that can be set in a number of ways. For example, either
\Drupal::configFactory() (for global code, such as in module hooks), or preferably via dependency injection (which probably means passing the 'config.factory' service into the constructor to set a protected property to access it from). The
$config_storage variable is similar, corresponding to the 'config.storage' service.
Here's a summary of my suggestions, by when you might want to use them:
|Even if inexistent||Only if existent|
|With overrides (read-only)|
|No overrides (read-only)||Check |
|Writable (no overrides)||Check |
That table deliberately leaves out a suggestion for getting writable config with overrides. That is because any type of config override may be updated in different ways. You may have to change values in the settings.php file, which you cannot do from the UI. Or use the core Configuration Translation module. Writing to config, including their overridden values, is outside the scope of this article ... and is outside the way that config is supposed to be used anyway! Read the documentation on drupal.org for more details, which includes how to deal with specific sets of overrides, like specific languages, or from modules.
Let's go into some detail about these ways of getting configuration.
$config_factory->get($id) (and its equivalents - see note below) is the simplest method, which will give you the current actual values of the config, including any translations or overrides from settings.php. But it gives you an 'immutable' configuration object, that can only be read, so is no good for updating. That is deliberate, since at least some sorts of config overrides can't be directly updated anyway. If you try to get a piece of config this way that doesn't exist, the config object you get can still be used, but won't hold any values. You can test for this by either checking that
FALSE or simply that
$config->get() is empty.
You can exclude overrides using the
->getRawData() method on the config object if you really want an immutable version without them.
$config_factory->get($id) is also identical to
\Drupal::config($id), which is even simpler, but should only be used from 'global' code like hooks in
Controllers that extend
ControllerBase or forms that extend
->config($id) methods that do almost the same thing too.
Forms that extend
ConfigFormBase are a bit special though, in that config returned by that method for any names returned by their
->getEditableConfigNames() implementations will be editable.
This will get you an 'editable' (mutable) piece of config, so guarantees you can set & save values on it (or even delete it). That does mean it won't contain any overrides, so may not be the actual values that would get used for pages, e.g. from settings.php or translations. However, note that as it guarantees an editable object, so you can call it for config that doesn't actually exist, which you might not want. See the above section about
\Drupal::config() for checks you can use, or skip to my next suggestions.
On this editable config object, you can even call the
->getOriginal() method to get back to the original loaded data from before any values were changed, using its parameters to do so for specific sub-values or to ignore any overrides.
If you want to check for the existence of some config, but don't need to make changes to it, this is the one to use. It might have been nicer if there was a
->load() method for just loading single items of config, but
loadMultiple() will have to do, just make sure to pass it an array :-) You will get an array back, which will be empty if the config doesn't exist, and otherwise contains immutable config objects, just like my first suggestion from above,
$config_factory->get($id). It will also include any overrides like translations.
As mentioned previously, you can use the
->get() methods to check when config returned from its factory does not actually exist. If you really want to, you can interrogate the config storage service directly, to get back the array of existing config data, or
FALSE if it doesn't. This gets a bit more low-level though, so I'd recommend against it really. As it returns an array, to actually save into a config object, the best option is to get the editable version from the factory as above and check
FALSE, or look into what the factory does with the data read from its storage.
Hopefully that helps you understand which method you might want to use for various needs, and why.