In Drupal 7, to manage system variables, we used variable_get() / variable_set() / variable_del() calls and stored those variables in the variable table of the database.
In Drupal 8 we now use the Configuration system which provides a central place for modules to store configuration data. This system allows to store information that can be synchronized between development and production sites. This information is often created during site building and is not typically generated by regular users during normal site operation.
In Drupal 8 configuration is still stored in the database, but it can now be synced with YML files on the disk for deployment purposes aswell.
In this post we will create a configuration form that stores a configuration value in our system. In this case it will be a form that stores the value of an external API key. Next, we will retrieve this value and use it in a very simple controller.
1. Create the module
2. Create the form
3. Check the form
4. Retrieve the config information in a controller
1. Create the module skeleton
We use the following Drupal Console command.
drupal generate:module \
--module="ex08" \
--machine-name="ex08" \
--module-path="modules/custom" \
--description="An simple example of a config form" \
--core="8.x" \
--package="Custom" \
--module-file \
--uri="http://default" \
--no-interaction
2. Create the form
To create the config form we use Drupal Console with the drupal generate:form:config
command.
drupal generate:form:config \
--module="ex08" \
--class="ExternalApiKeyForm" \
--form-id="external_api_key_form" \
--config-file \
--inputs='"name":"your_external_api_key", "type":"textfield", "label":"Your external API Key", "options":"", "description":"Enter your external API Key", "maxlength":"64", "size":"64", "default_value":"none", "weight":"0", "fieldset":""' \
--path="/admin/config/ex08/externalapikey" \
--uri="http://default" \
--no-interaction
This Drupal Console command will:
- create the config form file ExternalApiKeyForm.php under the src/form folder
- update or create the ex08.routing.yml file with a route to the config form to access it.
Now let’s see what this code is doing in detail.
3. The config form
If we now open the ExternalApiKeyForm.php
file we see the following code.
<?php
namespace Drupal\ex08\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Class ExternalApiKeyForm.
*/
class ExternalApiKeyForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'ex08.externalapikey',
];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'external_api_key_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('ex08.externalapikey');
$form['your_external_api_key'] = [
'#type' => 'textfield',
'#title' => $this->t('Your external API Key'),
'#description' => $this->t('Store the external API Key'),
'#maxlength' => 64,
'#size' => 64,
'#default_value' => $config->get('your_external_api_key'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$this->config('ex08.externalapikey')
->set('your_external_api_key', $form_state->getValue('your_external_api_key'))
->save();
}
}
Fist we see that the class ExternalApiKeyForm
extends ConfigFormBase abstract class which also extends the FormBase abstract class.
The ExternalApiKeyForm class has four basic methods:
getEditableConfigNames() - gets the configuration object name (The name of the configuration environment where we store or get the values). In our case we give it the name: 'ex08'.externalapikey'.
getFormId() - returns the form's unique ID. This will be the name of our form or its ID. In our case, we named it 'external_api_key_form'.
buildForm() - returns the form array. This method creates the form and in this case one item named 'your_external_api_key'. This item is a text field. We will also use this name for
the key of the key/value pair stored in the configuration.
We also get the current value for the key 'your_external_api_key' from the configuration object to set it as a default value for this field: '#default_value' => $config->get('your_external_api_key'),
validateForm() - validates the form.
submitForm() - processes the form submission. In this step, we will set and save the value of the key 'your_external_api_key' in the configuration system.
4. The route to the form
Drupal Console also updates or creates the ex08.routing.yml
file with a route to the config form to access it.
ex08.external_api_key_form:
path: '/admin/config/ex08/externalapikey'
defaults:
_form: '\Drupal\ex08\Form\ExternalApiKeyForm'
_title: 'ExternalApiKeyForm'
requirements:
_permission: 'access administration pages'
options:
_admin_route: TRUE
Nothing strange here. With path we define the URL to access the form. With _form we indicate the class which generates the form and with _title we define the title of the form. With _permission we give access to users who have permission to access administration pages (user access to the administration path).
Now that we have a form and a route, we can access the form from the URL /admin/config/ex08/externalapikey and test it.
5. Debug the configuration object.
We can also debug the configuration object with Drupal Console command debug:config (dc) which give us a list configuration objects names and single configuration object:
6. Retrieve the value in a controller class.
To get or set the value of a configuration object in a class, we will need a service. In fact we need the core service 'config.factory'.
We can find it with the Drupal Console commands: drupal debug:container
or drupal debug:container config.factory
This service has a method that allows to get the value by its key of a configuration object.
So, when we create the controller, well inject this service to use later.
Lets create the controller and inject the service at the same time with Drupal Console.
drupal generate:controller --module="ex08" \
--class="ExternalApiKeyController" \
--routes='"title":"External API Key", "name":"ex08.external_api_key_controller_ShowKey", "method":"ShowKey", "path":"/ex08/ShowKey"' \
--services='config.factory' \
--uri="http://default" \
--no-interaction
This command creates the file ExternalApiKeyController.php
under /src/Controller and update the ex08.routing.yml
file with a new route.
The updated ex08.routing.yml file:
ex08.external_api_key_form:
path: '/admin/config/ex08/externalapikey'
defaults:
_form: '\Drupal\ex08\Form\ExternalApiKeyForm'
_title: 'ExternalApiKeyForm'
requirements:
_permission: 'access administration pages'
options:
_admin_route: TRUE
ex08.external_api_key_controller_ShowKey:
path: '/ex08/ShowKey'
defaults:
_controller: '\Drupal\ex08\Controller\ExternalApiKeyController::ShowKey'
_title: 'External API Key'
requirements:
_permission: 'access content'
The new ExternalApiKeyController.php:
<?php
namespace Drupal\ex08\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\webprofiler\Config\ConfigFactoryWrapper;
/**
* Class ExternalApiKeyController.
*/
class ExternalApiKeyController extends ControllerBase {
/**
* Drupal\webprofiler\Config\ConfigFactoryWrapper definition.
*
* @var \Drupal\webprofiler\Config\ConfigFactoryWrapper
*/
protected $configFactory;
/**
* Constructs a new ExternalApiKeyController object.
*/
public function __construct(ConfigFactoryWrapper $config_factory) {
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory')
);
}
/**
* Showkey.
*
* @return array
*
*/
public function ShowKey() {
return [
'#type' => 'markup',
'#markup' => $this->t('The ShowKey() action')
];
}
}
We can see that the config.factory service has been retrieved from the service container in the create() method and sent back (dependency injection) to the class itself through the __construct() method. Thank you, Drupal Console!!!
Now, in the ShowKey() method, we need to access the value of our ex08.externalapikey
configuration object and get the value of the key your_external_api_key
. This is what we can see in the following code:
public function ShowKey() {
// Get the configuration object
$config = $this->configFactory->get('ex08.externalapikey');
// Get the value of the key 'your_external_api_key'
$key = $config->get('your_external_api_key');
return [
'#type' => 'markup',
'#markup' => $this->t('The External API Key is: @key',['@key'=>$key])
];
}
Done!!!
Recap.
1. We created a configuration form, and a route to this form, with the DC command drupal generate:form:config. This form generated a configuration object ('ex08.externalapikey') and a set of key/value pair. In our case, we have just one key/value pair and the key is: 'your_external_api_key'
2. We debugged the key/value pair of the configuration object with the DC command drupal debug:config <name-of-config-object>
3. We created a controller and injected the service we need (config.factory) to access the config system.
In the controller, we called the service object to get the value of a particular key of the configuration object.
As we can see, today Drupal Console is a must in Drupal 8.
7. Bonus: Retrieve the config value in a hook
Sometimes we need set or get configuration values in a hook, in this case we can't inject the service config.factory by dependency injection.
We’ll use the \Drupal
static service container wrapper to do so.
function ex08_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id){
// Get the config object
$config = \Drupal::config('ex08.externalapikey');
// Get the key value
$key = $config->get('your_external_api_key');
}
More info:
Configuration API overview (Drupal Docs.)
Managing your site's configuration (Drupal Docs.)
Creating a Simple Configuration Form in Drupal 8 (Third&Grove Blog)
The Drupal Static Service Container wrapper (Drupal API)