Overview

Configuration Management Overview

Configuration values are used in Concrete CMS to store configuration data for blocks, themes, packages, and the Concrete core. These values can be used for saving user preferences set through a dashboard page. Concrete provides interfaces to read and write these configuration values to the filesystem and to the database.

For storing configuration values in 5.7+, there is now a "ConfigRepository". A ConfigRepository has standard interfaces for reading and writing to a store. One for reading and writing to the filesystem "config" and one for reading and writing to the database "config/database". Both of these are instances of the same Repository class with different "Config\LoaderInterface" and "Config\SaverInterface" implementations injected.

When writing to the filesystem, the config values will be saved as arrays in PHP files within the application\config\generated_overrides folder. Values saved to the database will be stored in the Config table. Config values are stored using key value pairs. A key will have three parts: a configNamespace, a configGroup, and a configItem (filesystem config keys can have more than one configItem). The configNamespace is followed by two colons and the configGroup and configItem are separated by a dot - configNamespace::configGroup.configItem. If you separate the configNamespace and configGroup with a dot, the configNamespace will be treated as the configGroup - configNamespace.configGroup.configItem.

The primary methods for working with config values are get(), save(), set(), has(), and clear().
get($key, $default)
- get a config value that has been saved or set
- an optional default value can be added if the value is not found
save($key, $value)
- save a config value to the filesystem or to the database
set($key, $value)
- set a config value at runtime
- a temporary config value is created in memory for the current request and is discarded after the request completes
- set values can be used to override a saved value
has($key)
- check to see if a key has been saved or set
- returns a true or false boolean
clear($key)
- clear a config value
- clear() uses the set() method to set a config value to null

There are several ways to read and write config values:

  • Using a Package object
  • Using a service provider
  • Using Config

Using a Package object

When working within a package controller or working with a Package object, there is a "Repository\Liaison" class that will set the default configNamespace for the get(), save(), set(), has(), and clear() methods. The default configNamespace will be the package handle of the package object being used. The filesystem config liaison is getFileConfig() and the database config liaison is getConfig().

For example, if you'd like to add a toggleable option named "show_header" to your package and store the value in the database, your configItem would be "show_header", your configGroup should be something semantic like "front_end", and your configNamespace would be your package handle. This key would look like my_package::front_end.show_header. Remember that when using getConfig() and getFileConfig(), the configNamespace is added for you by the liaison.

Saving a config value to the database:

// get the package object
use Package; // or \Package::getByHandle('my_package') using the global namespace
$packageObject = Package::getByHandle('my_package');
// based on the value of $show_header, save the show_header toggle value to true or false
if ($show_header) {
    $packageObject->getConfig()->save('front_end.show_header', true);
} else {
    $packageObject->getConfig()->save('front_end.show_header', false);
}

After this code was run, you would see a new row in the Config database table for your saved key and config value.

configNamespace configGroup configItem configValue
my_package front_end show_header 1

Getting a config value from the database:

// get the package object
use Package; // or \Package::getByHandle('my_package') using the global namespace
$packageObject = Package::getByHandle('my_package');
// display the header code if show_header is true
$showHeader = $packageObject->getConfig()->get('front_end.show_header');
if ($showHeader) {
   // header code
}

Writing to the filesystem is just as easy, the only difference is getFileConfig() is used instead of getConfig(). In this next example, you are saving user preferences for an email add-on.

Saving config values to the filesystem:

// get the package object
use Package; // or \Package::getByHandle('my_package') using the global namespace
$packageObject = Package::getByHandle('my_package');
// save the preferences
$packageObject->getFileConfig()->save('email.update_schedule', 'daily');
$packageObject->getFileConfig()->save('email.show_images', false);
$packageObject->getFileConfig()->save('email.show_links', true);

After the config value preferences are saved, a new folder called "my_package" will be created in application\config\generated_overrides. In "my_package" there will be a PHP file called "email.php" that contains an array of configItems and values (the configNamespace is the name of the folder and the configGroup is the name of the PHP file).

application\config\generated_overrides\my_package\email.php

return array(
    'update_schedule' => 'daily',
    'show_images' => false,
    'show_links' => true,
);

Getting config values from the filesystem:

//get the package object
use Package; // or \Package global namespace
$packageObject = Package::getByHandle('my_package');
// get the preferences
$updateSchedule = $packageObject->getFileConfig()->get('email.update_schedule');
$showImages = $packageObject->getFileConfig()->get('email.show_images');
$showLinks = $packageObject->getFileConfig()->get('email.show_links');

Using a service provider

There are two service providers for working with config values: Core::make('config') and Core::make('config/database'). Core::make('config') writes values to the filesystem and Core::make('config/database') writes to the database. They work just like getFileConfig() and getConfig() except that the service providers do not add a default configNamespace for you and don't require a package object. Remember, the configNamespace and configGroup need to be separated with double colons or the configNamespace will be treated as the configGroup.

Write to the filesystem using Core::make('config'):

use Core; // or \Core::make('config') using the global namespace
$configFile = Core::make('config');
$configFile->get($key, $default);
$configFile->save($key, $value);
$configFile->set($key, $value);
$configFile->has($key);
$configFile->clear($key);

Write to the database using Core::make('config/database'):

use Core; // or \Core::make('config/database') using the global namespace
$configDatabase = Core::make('config/database');
$configDatabase->get($key, $default);
$configDatabase->save($key, $value);
$configDatabase->set($key, $value);
$configDatabase->has($key);
$configDatabase->clear($key);

Using Config

The Config facade works just like the Core::make('config') service provider.

use Config; // or \Config:: using the global namespace
Config::get($key, $default);
Config::save($key, $value);
Config::set($key, $value);
Config::has($key);
Config::clear($key);

Storing multiple values to a configItem

Storing multiple values to a configItem can be done by using an array as the value. When writing to the database, the configItem will be suffixed with a dot and a zero-based number. When writing to the filesystem, the configItem will be an array key and the config values will be an array of values.

Example: writing to the database

$this->getConfig()->save(
    'your_config_group.your_config_item',
    array(
        'your_config_value_1',
        'your_config_value_2',
        'your_config_value_3'
    )
);

Result:

configNamespace configGroup configItem configValue
your_package_handle your_config_group your_config_item.0 your_config_value_1
your_package_handle your_config_group your_config_item.1 your_config_value_2
your_package_handle your_config_group your_config_item.2 your_config_value_3

Example: writing to the filesystem

$this->getFileConfig()->save(
    'your_config_group.your_config_item',
    array(
        'your_config_value_1',
        'your_config_value_2',
        'your_config_value_3'
    )
);

Result: application\config\generated_overrides\your_package_handle\your_config_group.php

return array(
    'your_config_item' => array(
        'your_config_value_1',
        'your_config_value_2',
        'your_config_value_3',
    ),
);

Saving to the filesystem using multiple configItems

When writing to the database, you are limited to keys with three segments: configNamespace::configGroup.configItem. You don't have this limitation when writing to the filesystem. This allows you to create longer keys and add additional levels of nesting for your config values.

Example:

Config::save('your_package_handle::your_config_group.config_item_1.config_item_2.config_item_3.config_item_4.config_item_5.config_item_6', 'your_config_value');

Result: application\config\generated_overrides\your_package_handle\your_config_group.php

return array(
    'config_item_1' => array(
        'config_item_2' => array(
            'config_item_3' => array(
                'config_item_4' => array(
                    'config_item_5' => array(
                        'config_item_6' => 'your_config_value',
                    ),
                ),
            ),
        ),
    ),
);

Get the children of a configItem or configGroup

All configItem children (and their config values) of a configGroup can be retrieved by using only the configNamespace and configGroup portion of the key. When nesting multiple levels of configItems, you can retrieve the children of a specific configItem by including the configNamespace, configGroup, and the parent configItem. The result will be an array of all child configItems and their config values.

Example: get the children of a configGroup

$this->getFileConfig()->save('your_config_group.your_config_item_1', 'your_config_value_1');
$this->getFileConfig()->save('your_config_group.your_config_item_2', 'your_config_value_2');
$this->getFileConfig()->get('your_config_group');

Result:

array(2) {
  ["your_config_item_1"] => string(19) "your_config_value_1"
  ["your_config_item_2"] => string(19) "your_config_value_2"
}

Example: get the children of a configItem

$this->getFileConfig()->save('your_config_group.your_config_item_1.your_config_item_2.your_config_item_3_a', 'your_config_value_a');
$this->getFileConfig()->save('your_config_group.your_config_item_1.your_config_item_2.your_config_item_3_b', 'your_config_value_b');
$this->getFileConfig()->save('your_config_group.your_config_item_1.your_config_item_2.your_config_item_3_c', 'your_config_value_c');
$this->getFileConfig()->get('your_config_group.your_config_item_1.your_config_item_2');

Result:

array(3) {
    ["your_config_item_3_a"] => string(19) "your_config_value_a"
    ["your_config_item_3_b"] => string(19) "your_config_value_b"
    ["your_config_item_3_c"] => string(19) "your_config_value_c"
}

Saving associative arrays to the database

To save an associative array to the database, it first needs be converted to a storable format. Serializing and JSON encoding are two common ways to do this. Both approaches require the array to be converted before saving and then converted back again before being used. Serializing uses serialize() to convert the array and unserialize() to convert it back to the array PHP data type. JSON encoding uses json_encode() to convert the array to JSON (JavaScript Object Notation) and json_decode() to convert the array back to PHP. When using json_decode(), passing a second argument of true converts the JSON objects into associative arrays. Encoding to JSON can be useful if you are saving values that will be used in JavaScript. No additional steps are required to save associative arrays to the filesystem.

Serialize/Unserialize

Example: serialize() and save()

$this->getConfig()->save(
    'options.style',
    serialize(
        array(
            'name' => 'Large',
            'class' => 'h1.large'
        )
    )
);

Result:

configNamespace configGroup configItem configValue
your_package_handle options style a:2:{s:4:"name";s:5:"Large";s:5:"class";s:8:"h1.large";}

Example: get() and unserialize()

unserialize($this->getConfig()->get('options.style'));

Result:

array(2) {
    ["name"] => string(5) "Large"
    ["class"] => string(8) "h1.large"
}

JSON Encode/JSON Decode

Example: json_encode() and save()

$this->getConfig()->save(
    'options.style',
    json_encode(
        array(
            'name' => 'Large',
            'class' => 'h1.large'
        )
    )
);

Result:

configNamespace configGroup configItem configValue
your_package_handle options style {"name":"Large","class":"h1.large"}

Example: get() and json_decode()

json_decode($this->getConfig()->get('options.style'), true);

Result:

array(2) {
    ["name"] => string(5) "Large"
    ["class"] => string(8) "h1.large"
}