Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Apprendre à développer des applications web avec PHP et Symfony (2e édition)
  3. Les services
Extrait - Apprendre à développer des applications web avec PHP et Symfony (2e édition)
Extraits du livre
Apprendre à développer des applications web avec PHP et Symfony (2e édition)
2 avis
Revenir à la page d'achat du livre

Les services

Rappel sur les espaces de noms

Nous savons que nous récupérons les classes des objets que nous manipulons grâce à leur espace de noms et à Composer.

Une classe est localisée par son espace de noms défini en amont de celle-ci (instruction use).

Par exemple, si nous voulons utiliser la classe User dans un contrôleur, il faut que cette classe soit définie par son espace de noms : App\Entity\User.

Nous savons que l’espace de noms est par défaut déterminé par le chemin vers la localisation physique de la classe. La classe User est dans le dossier src/Entity, par conséquent, son espace de noms est déclaré comme suit :

Classe User :

<?php 
namespace App\Entity; 
... 
class User implements UserInterface 
{ 
... 
} 

À noter que nous utilisons l’alias App pour définir le dossier src. Cet espace de noms racine a été défini dans le fichier composer.json. Sous l’étiquette « autoload », nous retrouvons la définition de App :

 "autoload": { 
        "psr-4": { 
            "App\\": "src/" 
        } 
    }...

Notion de service

Votre application regorge de multiples objets utiles. Par exemple, l’objet « Mailer » vous permet d’envoyer des mails, un autre objet vous permet de stocker des éléments en base de données, etc.

À chaque utilisation de ces classes récurrentes, vous êtes obligé d’instancier les classes.

Il existe une « super » classe dans Symfony qui s’appelle le conteneur de service (service container). Son rôle est de s’occuper de l’instanciation des classes que vous souhaitez en amont de l’exécution de l’application.

En un mot, il fait tout à votre place !

Non seulement il vous permettra d’instancier automatiquement les classes, mais il instanciera également leurs dépendances. Par exemple, imaginons une classe NewsletterManager qui gère les newsletters. Cette classe va utiliser la classe Mailer pour envoyer les newsletters.

Si nous déclarons la classe NewsletterManager en tant que service, le conteneur de service instanciera cette classe, ainsi que la classe Mailer pour lui permettre de fonctionner.

Un autre avantage du conteneur de service est qu’il n’instancie la classe qu’une seule fois.

Si vous réutilisez un service que vous avez déjà utilisé, il vous redonnera l’objet déjà instancié...

Utilisation des services

Un certain nombre de services sont déjà, par défaut, disponibles dans votre application. Comment les connaître ?

Il suffit d’exécuter la commande suivante dans le terminal :

 php bin/console debug:autowiring 

Les services listés sont ceux qu’il est possible d’utiliser en injection de dépendance dans l’action d’un contrôleur, par exemple (autowiring).

Il existe beaucoup plus de services dans le conteneur. Pour une liste complète, vous pouvez exécuter la commande :

 php bin/console debug:container 

Prenons le service LoggerInterface par exemple, qui permet d’envoyer des messages dans le log. Nous observons sa classe en exécutant la première commande :

 php bin/console debug:container 
images/20RI01N.PNG

La classe est définie par son espace de noms : Psr\Log\LoggerInterface, mais aussi par un identifiant unique. Par exemple, la classe de base est définie par l’identifiant monolog.logger. Un identifiant particulier est défini pour chaque type de log, comme par exemple, monolog.logger.cache pour les messages mis en cache.

Nous pouvons utiliser le service LoggerInterface directement à l’aide de son espace de noms en utilisant ce qu’on appelle l’autowiring. Il s’agit de pouvoir injecter le service directement dans une méthode (une action d’un contrôleur...

Création de son propre service

Il est possible d’inscrire ses propres classes en tant que service dans le conteneur de service.

Nous allons créer un exemple avec un service qui génère des messages aléatoires. 

Créons un dossier Service sous le dossier src et créons le fichier src/Service/MessageGenerator.php :

<?php 
namespace App\Service; 
 
class MessageGenerator 
{ 
    public function getHappyMessage() 
    { 
        $messages = [ 
            'Bravo vous êtes le meilleur !', 
            'Ceci est le meilleur service que j\'ai vu ', 
            'Beau travail ! Continuez ! ', 
        ]; 
 
        $index = array_rand($messages); 
 
        return $messages[$index]; 
    } 
} 

La méthode array_rand() retourne aléatoirement un message du tableau $messages.

Comment déclarer cette classe dans le conteneur de service ?

C’est déjà...

Injection d’un service dans un service

Pour injecter un service dans le constructeur d’un service (injection de dépendances), nous allons le définir en argument dans le fichier config/services.yml.

Prenons l’exemple de notre service : App\Service\MessageGenerator. Nous souhaitons que ce service utilise le service LoggerInterface en autowiring. Nous pouvons lui passer l’identifiant du service en argument.

Nous vous rappelons que vous pouvez retrouver la liste des services et leurs identifiants grâce à l’instruction php/bin/console debug.

Dans le fichier config/services.yaml, ajoutons ces lignes :

    App\Service\MessageGenerator: 
        arguments: 
            $logger: '@monolog.logger' 

Le @ signifie à Symfony que nous passons un identifiant de service en argument et pas une chaîne de caractères.

Le paramètre $logger sera injecté automatiquement dans le constructeur du service App\Service\MessageGenerator. Modifions cette classe pour qu’elle puisse utiliser LoggerInterface :

<?php 
namespace App\Service; 
use Psr\Log\LoggerInterface; 
 
class MessageGenerator 
{ 
 
    public function __construct(LoggerInterface $logger) 
    { 
    } ...