Aller au contenu principal
Julien Dubois

Drupal 10 : Conteneur de Services et Services

Ce billet a été produit dans le contexte d'Happyculture, il a pu être écrit en collaboration.

Cet article a été initialement rédigé pour Drupal 8 mais son contenu est toujours d'actualité pour Drupal 9 et Drupal 10.


Comprendre le fonctionnement du conteneur de Service dans Drupal et la création de services.

Les applications modernes s’appuyant sur la POO, beaucoup d’objets sont impliqués dans le cycle de vie d’une page. Afin de vous épargner la création, la réutilisation et la suppression de chacun de ces nombreux objets, depuis Drupal 8, Drupal s’appuie sur un objet spécial de Symfony appelé Service Containerqui vise à vous simplifier la manipulation de ces dits objets.
Comme son nom l’indique, le Conteneur de Services gère des Services.

Un Service représente une fonctionnalité réutilisable à travers votre site (accès à la base de données, envoi d’un mail, traduction une chaîne, etc).
Si l’on prend l’exemple de la base de données, imaginez que vous ayez à configurer le nom d’utilisateur, le mot de passe et le nom de la base. Que vous soyez dans un environnement de production ou de développement, vous n’aurez probablement pas les mêmes valeurs. Si vous deviez saisir les nouvelles informations de connexion il vous faudrait passer par une recherche et remplacement de ces données à travers votre base de code. Cette action étant plutôt laborieuse, les Services permettent de simplifier cette gestion. En ayant une définition centralisée et découplée, il devient plus facile de les réutiliser, de les étendre ou de les remplacer.

Exemple de l’utilisation d’une classe pour encoder quelque chose en JSON :

# Controller.php
use Drupal\Component\Serialization\Json;

$json_serializer = new Json();
$json_serializer->encode(...);

Conversion en Service :

# core.services.yml
services:
  serialization.json:
    class: Drupal\Component\Serialization\Json

Exemple d’utilisation du Service :

# Controller.php
$service = \Drupal::service('serialization.json');
$service->encode(...);

C’est seulement lorsque l’appel au Service est fait que l’objet est créé et retourné, pas avant qu’il ne soit nécessaire. Cette instanciation tardive augmente les performances de l’application (pas de gaspillage) et surtout permet de facilement remplacer l’implémentation d’un Service, principe très important pour réaliser des tests unitaires.

Dans le quotidien de vos projets vous serez amenés à créer peu de nouveaux Services, mais il est fort à parier que vous aurez à modifier des Services existants pour surcharger des comportements, simuler la génération de données (pour les tests notamment).

Pour cela, il vous suffit d’implémenter une classe qui étend ServiceProviderBase et qui possède une méthode alter() dans laquelle sera décrite la surcharge.

# src/MyModuleServiceProvider.php
namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

class MyModuleServiceProvider extends ServiceProviderBase {
  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    // Remplace la classe qui implémente le service "language_manager".
    $definition = $container->getDefinition('language_manager');
    $definition->setClass('Drupal\language_test\LanguageTestManager');
  }
}

Certains des Services que vous implémenterez auront besoin d’arguments pour fonctionner. Ces arguments peuvent être des paramètres. Un paramètre est une donnée variable qui peut être définie dans un fichier centralisé. Les paramètres utilisés par un Service sont entourés du symbole % pour indiquer qu’il s’agit de paramètres.

Exemple :

# module.services.yml
services:
twig:
 class: Drupal\Core\Template\TwigEnvironment
 arguments: ['@app.root', '@cache.default', '%twig_extension_hash%', '@twig.loader', '%twig.config%']

Les paramètres peuvent être définis directement dans le fichier de déclaration des services ou dans un autre fichier. Notez que si votre chaîne contient un @, il faut l’échapper en doublant l’arobase. Dans l’exemple ci-dessus vous voyez le paramètre %twig.config% dont la valeur par défaut est définie dans le fichier core.services.yml mais que vous pouvez surcharger dans votre fichier services.yml (dans sites/default).

Découvrez maintenant comment appeler et injecter les dépendances de vos plugins, services ou hooks.

Pour rebondir