Skip to content

Principes de base

Ronan Lenouvel edited this page Jan 10, 2023 · 7 revisions

Le container de services

Le travail du container de service, c'est de préparer des outils pour les rendre facilement et rapidement disponibles à l'utilisation.

On peut connaitre tous ces services avec la commande :

symfony console debug::autowiring --all

Les services présents dans cette longue liste, sont passés par référence afin de ne pas compromettre les performances.

Un Controller, peut recevoir grâce au type-hinting n'importe lequel de ces services, car il est associé à une route pour la gestion de la requête.

#[Route('/', name: 'homepage')]
NomDeMonController(Service $service)
{
 ...
}

Cette "magie" est rendue possible, en partie grâce à plusieurs fichiers:

image

config/bundles.php, lui s'occupe d'injecter dans le container de services, tous les bundles du framework grâce au composant Symfony Flex.

Rien d'autre à faire ! Dès qu'un bundle est installé, il est ajouté a cette liste.

image

config/services.yaml quand à lui, permet de paramétrer un peu plus en profondeur.

parameters:

services:
    # default configuration for services in this file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'

A noter, avec cette configuration l'ensemble du dossier /src est automatiquement injecté.

il faut préciser les sous-dossiers à exclure, ici 3, /src/DependencyInjection/, /src/Entity/, /src/Kernel.php.

La clef autowiring ayant pour valeur true, cela va ainsi permettre d'aller 'piocher' rapidement dans le container de service le service souhaité.

Exemple: Une classe à besoin d'un service

namespace App\Service;

use App\Util\Service;

class JaiBesoinDunService
{
    private $transformer;

    public function __construct(Service $transformer)
    {
        $this->transformer = $transformer;
    }

    public function faireQuelqueChose($s): void
    {
        $serviceRendu= $this->transformer->operate($s);
    }
}
namespace App\Util;

class Service
{
    public function operate(string $s): string
    {
        return (string)$s;
    }
}

Avec la configuration par défaut les deux classes sont automatiquement enregistrées en tant que services et configurées pour être câblées automatiquement . On peut donc les utiliser sans aucune configuration.

Il est aussi possible les déclarer dans services.yaml mais c'est redondant:

services:
    _defaults:
        autowire: true
        autoconfigure: true
    # ...

    App\Service\JaiBesoinDunService:
        autowire: true

    App\Util\Service:
        autowire: true

Toutefois injecter des services dans le container de cette méthode est envisageable.

Si l'on souhaite aller plus loin il est possible de créer des alias, où par exemple l'id n'est pas un nom de classe.

# config/services.yaml
services:
    # ...

    # the id is not a class, so it won't be used for autowiring
    app.service.transformer:
        class: App\Util\Service
        # ...

    # but this fixes it!
    # the ``app.service.transformer`` service will be injected when
    # an ``App\Util\Service`` type-hint is detected
    App\Util\Service: '@app.service.transformer'

Les alias sont utilisés par les bundles principaux pour permettre aux services d'utiliser l'autowiring. Par exemple, MonologBundle crée un service dont l'id est logger. Mais il ajoute également un alias : Psr\Log\LoggerInterface qui pointe vers le loggerservice. C'est pourquoi les arguments avec indication de type Psr\Log\LoggerInterface peuvent être câblés automatiquement.

ℹ️ Il est possible d'aller encore plus loin par exemple pour travailler avec des interfaces.

Clone this wiki locally