Au sujet de la persistance des données
Nous avons vu dans le point précédent qu'une fois qu'un formulaire a été validé, nous pouvons persister l'entité puis flush.
Pour faire ça, nous avons utilisé une variable $em.
Cette variable est en fait injectée directement dans le contrôleur sous forme de paramètre.
Pour expliquer sommairement le fonctionnement de cette injection, nous devons parler de nouveau du système d'injection de dépendances dans Symfony.
Pour injecter un service dans un contrôleur par exemple, nous avons vu que nous pouvions utiliser les type-hints.
Quand on utilise un type-hint, Symfony recherche le service correspondant (la classe) dans le container de services.
Ainsi, s'il trouve un service, il peut injecter une instance de celui-ci là où nous en avons besoin.
Cependant, les services qui peuvent être injectés par un type-hint doivent être autowirés.
Pour résumer, un service autowiré, qui utilise donc l'autowiring de Symfony, peut donc être type-hinté dans une méthode de contrôleur, ou dans le constructeur d'une classe.
Dans notre application, toutes les classes qu'on crée dans src/ sont enregistrées comme services, et autowirées : on peut les type-hinter dans les paramètres d'un contrôleur ou d'un constructeur de classe
La question à se poser est donc la suivante : pour pouvoir communiquer avec ma base de données, quel type de classe vais-je pouvoir type-hinter dans les paramètres de mon contrôleur ?
Avec la console de Symfony, nous pouvons explorer les services autowirés.
Ici, nous voulons un entity manager, un gestionnaire d'entités.
Nous allons utiliser la commande debug:autowiring. Nous pouvons lui passer un argument de recherche pour qu'il affiche le ou les types correspondants :
php bin/console debug:autowiring entity
Et en sortie, Symfony nous affiche :
Autowirable Types
=================
The following classes & interfaces can be used as type-hints when autowiring:
(only showing classes/interfaces matching entity)
EntityManager interface
Doctrine\ORM\EntityManagerInterface (doctrine.orm.default_entity_manager)
Doctrine\ORM\EntityManagerInterface $defaultEntityManager (doctrine.orm.default_entity_manager)
Nous allons donc pouvoir type-hinter l'interface EntityManagerInterface du package Doctrine :
public function index(
Request $request,
EntityManagerInterface $em
): Response {
$newsletter = new Newsletter();
$form = $this->createForm(NewsletterType::class, $newsletter);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($newsletter);
$em->flush();
}
//...
}
Au passage, nous retrouvons notre autre type-hint, Request.
Le rôle de l'autowiring est donc d'identifier un type-hint et nous fournir le service correspondant. Cela facilite donc l'utilisation de services au sein de l'application
Nous ne détaillerons pas dans ce module la raison pour laquelle nous devons injecter une interface et non une classe pour l'entity manager
Dans notre application, la configuration par défaut rend tous nos services autowirés. C'est pourquoi nous pouvons injecter nos repositories directement dans nos contrôleurs, sans configurer manuellement quoi que ce soit.
À la lecture du type-hint, Symfony ira chercher s'il existe un service dont l'ID est ce FQCN (le type-hint complet). Étant donné que l'ID par défaut de nos services est leur FQCN, alors nous n'avons rien besoin de configurer pour pouvoir injecter nos services.