En Drupal 7, nous gérions les variables système avec variable_get() / variable_set() / variable_del(), stockées dans la table variable. Depuis Drupal 8, ce rôle revient au système de Configuration : un lieu centralisé où les modules enregistrent leurs réglages, exportables en YAML sur le disque et synchronisables entre environnements. La configuration reste en base de données à l'exécution, mais elle peut être déployée sous forme de fichiers, le modèle sur lequel repose tout ce site.
Dans ce post, nous allons construire un formulaire de configuration qui enregistre une seule valeur, une clé d'API externe, puis nous la relirons dans un contrôleur. Sept sections :
- générer le module et le formulaire,
- déclarer le schéma de configuration,
- écrire le formulaire de configuration,
- ajouter la route,
- inspecter la configuration enregistrée,
- relire la valeur dans un contrôleur,
- bonus : la lire dans un hook.
1. Générer le module et le formulaire
Drupal Console n'existe plus ; c'est désormais Drush 13 qui embarque le générateur de code. Créons le module et un formulaire de configuration :
drush generate module
drush generate form:config
Le générateur form:config écrit la classe du formulaire dans src/Form/, ajoute une route dans ex08.routing.yml et (point important en Drupal 11) vous rappelle de déclarer un schéma de configuration. Depuis Drupal 10, ConfigFormBase valide les valeurs enregistrées contre un schéma : un formulaire de config sans schéma lève une erreur à l'envoi.
2. Le schéma de configuration
Créez config/schema/ex08.schema.yml décrivant notre objet de configuration et son unique clé :
ex08.externalapikey:
type: config_object
label: 'External API key settings'
mapping:
your_external_api_key:
type: string
label: 'Your external API key'
3. Le formulaire de configuration
Voici le formulaire complet en Drupal 11. Il étend ConfigFormBase et ne surcharge que quatre méthodes. Regardons d'abord la classe entière, puis parcourons les méthodes clés.
<?php
declare(strict_types=1);
namespace Drupal\ex08\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Stores and edits the external API key.
*/
final class ExternalApiKeyForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames(): array {
return ['ex08.externalapikey'];
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'external_api_key_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$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' => $this->config('ex08.externalapikey')->get('your_external_api_key'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$this->config('ex08.externalapikey')
->set('your_external_api_key', $form_state->getValue('your_external_api_key'))
->save();
parent::submitForm($form, $form_state);
}
}
ExternalApiKeyForm étend la classe abstraite ConfigFormBase. Ses quatre méthodes :
- getEditableConfigNames() : le ou les objets de configuration que ce formulaire peut écrire ; ici
ex08.externalapikey. - getFormId() : l'identifiant unique du formulaire,
external_api_key_form. - buildForm() : construit le tableau de rendu. Notre unique champ,
your_external_api_key, initialise sa#default_valuedepuis la config courante afin d'afficher ce qui est déjà stocké. - submitForm() : réécrit la valeur envoyée dans la config puis appelle
parent::submitForm(), qui affiche le message standard « configuration enregistrée ».
Nous ne surchargeons plus validateForm() juste pour appeler le parent : ce code inutile n'a plus lieu d'être. À noter aussi qu'en Drupal 11, ConfigFormBase n'a plus besoin d'un constructeur écrit à la main pour injecter config.factory ; la classe de base s'en charge. Plutôt simple, non ?
4. La route
Le générateur a écrit une route pour le formulaire dans ex08.routing.yml :
ex08.external_api_key_form:
path: '/admin/config/ex08/externalapikey'
defaults:
_form: 'Drupal\ex08\Form\ExternalApiKeyForm'
_title: 'External API key'
requirements:
_permission: 'access administration pages'
options:
_admin_route: TRUE
path indique l'URL du formulaire, _form nomme la classe qui le construit, _title est le titre de la page et _permission restreint l'accès aux utilisateurs autorisés à atteindre les pages d'administration. Rendez-vous sur /admin/config/ex08/externalapikey pour le tester.
5. Inspecter la configuration enregistrée
Avec Drush 13, vous lisez les objets de configuration directement en ligne de commande, sans passer par Drupal Console :
# Lister les objets de config qui contiennent « ex08 ».
drush config:status
drush config:get ex08.externalapikey
6. Relire la valeur dans un contrôleur
Pour lire une valeur de configuration dans une classe, il nous faut le service config.factory. Nous l'injectons avec le trait de cœur AutowireTrait, ce qui évite d'écrire une méthode create() à la main.
<?php
declare(strict_types=1);
namespace Drupal\ex08\Controller;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\AutowireTrait;
/**
* Displays the stored external API key.
*/
final class ExternalApiKeyController extends ControllerBase {
use AutowireTrait;
public function __construct(
protected readonly ConfigFactoryInterface $configFactory,
) {}
/**
* Shows the value stored under the "your_external_api_key" key.
*/
public function showKey(): array {
$key = $this->configFactory->get('ex08.externalapikey')->get('your_external_api_key');
return [
'#markup' => $this->t('The external API key is: @key', ['@key' => $key]),
];
}
}
L'exemple original en Drupal 8 typait Drupal\webprofiler\Config\ConfigFactoryWrapper, un wrapper de débogage qui ne devrait jamais apparaître dans du vrai code. Le type correct est \Drupal\Core\Config\ConfigFactoryInterface, que nous autowirons ici.
Ajoutez la route du contrôleur à ex08.routing.yml :
ex08.external_api_key_controller_show_key:
path: '/ex08/show-key'
defaults:
_controller: 'Drupal\ex08\Controller\ExternalApiKeyController::showKey'
_title: 'External API key'
requirements:
_permission: 'access content'
7. Bonus : lire la valeur dans un hook
Il arrive qu'on ait besoin d'une valeur de config là où l'injection de dépendances est peu commode, par exemple dans un hook procédural. Le wrapper statique \Drupal est alors le choix pragmatique :
function ex08_form_alter(array &$form, \Drupal\Core\Form\FormStateInterface $form_state, string $form_id): void {
$key = \Drupal::config('ex08.externalapikey')->get('your_external_api_key');
// ...
}
(En Drupal 11 vous pouvez aussi déplacer les hooks dans une classe orientée objet avec l'attribut #[Hook] et injecter proprement config.factory, mais le wrapper statique reste acceptable pour une simple lecture.)
En résumé. Nous avons généré un module et un formulaire ConfigFormBase avec drush generate, déclaré le schéma de configuration obligatoire, stocké une paire clé/valeur dans l'objet ex08.externalapikey, inspecté celui-ci avec drush config:get, puis relu la valeur dans un contrôleur via le service config.factory autowiré.
Comment stockez-vous vos propres clés d'API et vos secrets dans Drupal ? Dites-le-moi dans les commentaires, je suis toujours curieux de savoir comment les autres s'y prennent.
Pour en savoir plus
- Configuration API overview (docs Drupal)
- Simple configuration API (docs Drupal)
- The Drupal static service container wrapper (API Drupal)