Système de remplacement (override) de configuration
Le système de configuration de Drupal 8 gère la configuration de manière unifiée. Par défaut, Drupal stocke les données de configuration en base de données, mais elles peuvent être exportées en fichiers YAML, ce qui permet de gérer la configuration via le contrôle de version. Cependant, il existe des cas où il faut remplacer certaines valeurs de configuration pour des besoins spécifiques. Dans Drupal 7, il y avait une variable globale $conf, généralement remplie dans settings.php avec des valeurs conditionnelles de remplacement. Un gros problème avec ce système était que ces remplacements entraient dans la configuration réelle. Quand un formulaire de configuration contenant des valeurs remplacées était sauvegardé, le remplacement conditionnel était enregistré dans la configuration effective.
Drupal 8 introduit un système de remplacement de configuration qui :
- Supporte ces remplacements comme des couches temporaires au-dessus des valeurs standard de configuration
- N’utilise pas les valeurs remplacées dans les formulaires de configuration
- Peut stocker les remplacements avec d’autres fichiers de configuration pour supporter le staging et le contrôle de version (par exemple pour les remplacements liés aux langues ; voir ci-dessous).
La variable globale $conf de Drupal 7 est renommée en $config dans Drupal 8 et activée par défaut dans le système de configuration.
Remplacements globaux
Drupal 8 conserve la possibilité d’utiliser global $config. Le système de configuration fusionne ces valeurs de remplacement via la méthode Drupal\Core\Config\ConfigFactory::get(). Quand vous récupérez une valeur de configuration, la variable globale $config a la possibilité de modifier la valeur retournée :
// Récupérer le message de maintenance du site. Cette valeur peut être remplacée par défaut depuis le global $config (et aussi les traductions, voir plus bas). $message = \Drupal::config('system.maintenance')->get('message');
Pour remplacer des valeurs dans le global $config, par exemple dans settings.php, adressez-vous aux clés de configuration :
$config['system.maintenance']['message'] = 'Sorry, our site is down now.';
Pour les valeurs imbriquées, utilisez les clés de tableau imbriqué :
$config['system.performance']['css']['preprocess'] = 0;
En dehors de settings.php, pour utiliser $config, référez-vous à l’ancien global $config ;
Il peut être utile de voir quelles variables de configuration sont disponibles par :
- les consulter avec le module « Configuration Manager » via l’interface /admin/config/development/configuration/single/export
- vérifier les fichiers YAML de configuration du site directement,
- ou les demander avec drush.
drush config-list drush config-get system.performance --include-overridden
Notez que les valeurs remplacées via $config dans settings.php ne sont pas visibles dans l’interface d’administration Drupal (jusqu’à #2408549 : les formulaires ne montrent pas si une valeur est remplacée), sauf si vous utilisez Configuration Override Warn ou Config Override Inspector), ni dans drush sans le flag --include-overridden. L’interface d’administration montre les valeurs sauvegardées dans la configuration, permettant de modifier les autres environnements ne possédant pas ces remplacements.
Un exemple de remplacement de clés API pour des raisons de sécurité est disponible ici : Remplacement des clés API du Commerce Gateway.
Éviter les remplacements
Vous pouvez récupérer la configuration sans les remplacements pour obtenir la valeur brute (utile pour ne pas appliquer les remplacements globaux). Cela est très utile notamment pour écrire des formulaires de configuration, afin que les valeurs remplacées ne soient pas écrites dans la configuration sauvegardée. C’est aussi utile en environnement multilingue où la configuration est souvent remplacée par des traductions.
Exemples de récupération avec et sans remplacements :
// Récupérer le nom du site, avec remplacements. $site_name = \Drupal::config('system.site')->get('name'); // Récupérer le nom du site sans remplacements. $site_name = \Drupal::config('system.site')->getOriginal('name', FALSE); // Notez que la configuration mutable est toujours sans remplacement. $site_name = \Drupal::configFactory()->getEditable('system.site')->get('name');
Vous pouvez aussi accéder au stockage de configuration directement via le service config.storage, qui implémente StorageInterface::read(). Cependant, ce n’est généralement pas la bonne manière d’accéder à la configuration.
Remplacements linguistiques
Par exemple, pour envoyer un e-mail à un utilisateur, sa configuration doit être dans la langue de l’utilisateur, pas celle de la page. On mémorise la langue originale, on définit la langue cible selon l’utilisateur, on effectue les opérations sur la configuration, puis on remet la langue d’origine :
// Charger le service language_manager $language_manager = \Drupal::service('language_manager'); // Récupérer l’objet langue cible $langcode = $account->getPreferredLangcode(); $language = $language_manager->getLanguage($langcode); // Mémoriser la langue originale $original_language = $language_manager->getConfigOverrideLanguage(); // Définir la langue cible pour la configuration. $language_manager->setConfigOverrideLanguage($language); $mail_config = \Drupal::config('user.mail'); // Envoyer l’e-mail basé sur $mail_config dans la bonne langue. // Remettre la langue de configuration. $language_manager->setConfigOverrideLanguage($original_language);
Le système de remplacements linguistiques utilise aussi le stockage de configuration pour garder les remplacements (contrairement aux remplacements globaux basés sur $config). Les fichiers de remplacement linguistique sont nommés selon leur fichier source, par exemple language.config.$langcode.user.mail.yml. Le préfixe language.config, suivi du code langue, puis du nom de la configuration originale. Ce stockage dans des fichiers distincts permet un staging et versionning progressifs des traductions.
Comment ces fichiers sont-ils créés ? Un module local s’intègre aux événements système pour générer ces fichiers de traduction basés sur la définition de schéma de configuration. Un module principal, Config Translation, fournit l’interface utilisateur pour traduire la configuration, aussi bien pour la configuration livrée que personnalisée, utilisant ces mêmes fichiers de remplacement linguistique.
Fournir des remplacements depuis les modules
Il est aussi possible de fournir des remplacements au niveau module depuis n’importe quel module. Alors que Drupal Core supporte les remplacements globaux et linguistiques, il existe des cas d’usage pour d’autres types, comme ceux basés sur le rôle utilisateur, le contexte, le domaine, les groupes, etc. Les modules peuvent définir leurs propres critères pour appliquer ces remplacements.
Quand ConfigFactory rassemble les remplacements fournis par les modules, il appelle tous les services marqués avec le tag config.factory.override :
config_example.services.yml
services: config_example.overrider: class: Drupal\config_example\Config\ConfigExampleOverrides tags: - {name: config.factory.override, priority: 5}
Vous pouvez définir la priorité des abonnés pour indiquer l’ordre des remplacements. Les remplacements à priorité plus élevée ont priorité sur ceux à priorité plus faible (pour une même configuration).
src/Config/ConfigExampleOverrides.php
namespace Drupal\config_example\Config; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Config\ConfigFactoryOverrideInterface; use Drupal\Core\Config\StorageInterface; /** * Exemple de remplacement de configuration. */ class ConfigExampleOverrides implements ConfigFactoryOverrideInterface { /** * {@inheritdoc} */ public function loadOverrides($names) { $overrides = array(); if (in_array('system.site', $names)) { $overrides['system.site'] = ['name' => 'Overridden site name!']; } return $overrides; } /** * {@inheritdoc} */ public function getCacheSuffix() { return 'ConfigExampleOverrider'; } /** * {@inheritdoc} */ public function getCacheableMetadata($name) { return new CacheableMetadata(); } /** * {@inheritdoc} */ public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) { return NULL; } }
Les remplacements de configuration opèrent sur trois niveaux différents : langue, modules et settings.php, ce dernier ayant la priorité la plus haute. Les remplacements dans settings.php ont priorité sur ceux fournis par les modules. Ceux des modules ont priorité sur ceux liés à la langue. La priorité des abonnés aux événements de remplacements module définit seulement la priorité entre modules, elle ne permet pas d’outrepasser la priorité langue ou settings.php.
Notez que les formulaires de configuration du Core Drupal n’utilisent pas les valeurs remplacées. Dans l’exemple ci-dessus, vous ne verrez pas « Overridden site name! » dans /admin/config/system/site-information.
Rappel important : si vous devez lire les valeurs originales dans un remplacement (par exemple pour comparer ou fusionner), chargez la configuration via \Drupal::configFactory et non \Drupal::config, afin d’éviter un cycle infini dans votre remplacement :
$original = \Drupal::configFactory()->getEditable('system.site')->getOriginal('name', FALSE);
Informations complémentaires
Le système de remplacement tel qu’il existe actuellement a été introduit dans #2098119 : Remplacer le système contextuel config par un support natif de locale et remplacements sur un seul événement.
Pour l’historique, voir aussi #1646580 : Implémenter événements et écouteurs de configuration et contextes de stockage pour la configuration localisée (qui introduit la première version du système de remplacement), ainsi que #1763640 : Introduire le contexte de configuration pour rendre les valeurs sources accessibles et d’autres remplacements, qui ont permis de supporter l’accès contextuel. Les remplacements spécifiques à la langue ont été ajoutés plus tard dans #2020361 : Créer LanguageConfigContext pour activer les remplacements de configuration basés sur la langue.