Web

Utiliser les controllers invokables dans Symfony

by Stéphane Meaudre 12 mai 2022

L’édition 2022 du Symfony Live a eu lieu le 7 et 8 avril à Paris pour cette première édition en présentiel. Lucie Barthes et moi-même, Stéphane Méaudre, tous deux développeurs back end, avons eu la chance de nous rendre à la Cité Internationale Universitaire de Paris pour assister à ce bel événement.

Dans le monde de Symfony, les controllers sont les portes d’entrées du framework: ils acceptent en argument un objet Request représentant une requête HTTP et renvoient un objet Response qui peut être un JSON, du XML, un template HTML etc. 

Qu’est ce que c’est ?

Couche issue du pattern design MVC, il est le lien entre la couche Model (récupération des données, persistance, etc.) et la couche View (affichage et restitution de ces données). C’est ainsi qu’une URL, nommée une route dans Symfony, va être associée à une action d’un controller, c’est-à-dire à une méthode de notre controller et va restituer les données à l’utilisateur.

Les exemples de code ci-dessous sont en PHP 7.4 et compatible Symfony 3.3+, 4.*, 5.*.

Comment cela se met en place ?

L’usage classique d’un controller se présente de cette façon :

Cliquez ici pour accéder au code

Code figure 1
Exemple basique d’utilisation d’une classe avec __invoke() :Dans la documentation de Symfony, il est précisé qu’il est possible d’utiliser des controllers invokables. Avant de rentrer dans le vif du sujet, petit rappel sur la fonction PHP __invoke(). Faisant partie des méthodes “magiques” de PHP et introduit depuis la version 5.3, cette méthode est appelée quand nous souhaitons utiliser un objet comme une fonction.

Cliquez ici pour accéder au code

Code figure 2

De cette façon nous pouvons créer une classe invokable qui va faire office de controller, se rapprochant ainsi des pratiques du design pattern ADR (Action-Domain-Responder), mais qui va également étendre la classe parente AbstractController de Symfony.

Reprenons notre exemple ci-dessus et modifions le un peu :

Cliquez ici pour accéder au code

Code figure exemple 3

 

Pour information, étendre le AbstractController n’est pas une obligation si les controllers sont déclarés en tant que services (fonctionnalité disponible depuis Symfony 3.3), mais l’inconvénient est que nous perdons l’utilisation de méthodes parentes utiles et il faut donc injecter nous-même certains services essentiels, tels Environment pour les templates, l’EntityManager, le Form Factory, le routing etc.

Exemple de controller (sans le controller parent de Symfony) :

Cliquez ici pour accéder au code

Figure 4

Si vous préférez utiliser le routing.yaml pour définir vos routes plutôt que les annotations (je ne vous juge pas sur ce choix ^^), voici comment déclarer la route et le controller :

Cliquez ici pour accéder au code

Invokable code

 

De la même façon, si on a besoin d’appeler un controller depuis un template à l’aide des fonctions twig render et render_esi

Cliquez ici pour accéder au code

Code exemple 6

Attention, il est très important de mettre les doubles antislashes; et petite particularité pour le render_esi: il est nécessaire de préciser la méthode “__invoke” dans l’argument.

À Kaliop nous utilisons le CMS Ibexa (ex-ezPlatform/ezPublish) qui est basé sur Symfony. De cette façon, on peut donc tout à fait utiliser les controllers invokable pour appliquer les surcharges sur les types de contenus :

Exemple sur le fichier override.yaml avec un type de contenu “article” :

Cliquez ici pour accéder au code

Exemple code Ibexa

 

L’override va automatiquement appeler le controller Article.php qui ressemble à ceci :

Cliquez ici pour accéder au code

Exemple 8 code

En conclusion, ce procédé a des points positifs et intéressants qui vont amener à une très grande simplification du code et un allègement des classes. Il y aura certes beaucoup plus de controllers mais ils seront identifiables beaucoup plus rapidement. Fini les énormes controllers remplis de méthodes et difficile à s’y retrouver.

Ce qu’il faut retenir 

  • une route = un controller = une action et par conséquent un allègement du code résultant une simplification de lecture et de compréhension si un autre développeur doit intervenir
  • Notre classe n’a plus qu’une seule responsabilité: restituer uniquement les données de son contexte à la vue, respectant ainsi le concept “Single Responsability” issue de SOLID
  • Granularité au niveau de notre couche Controller permettant de décorréler en partie la classe de son framework

Nous verrons dans un prochain article comment utiliser les controllers invokable et la mise en place du pattern ADR évoqué plus haut dans un projet Symfony.

 

Je remercie tout particulièrement Arnaud Tiérant, lead tech/senior software developper,  pour la relecture de l’article.

 

Stéphane Meaudre

Stéphane Meaudre

Développeur PHP à Kaliop depuis 2014 et passionné d'astronomie, j'aime réfléchir à l'architecture et à la conception de mon code avant tout. C'est pour ces raisons que j'apprécie fortement de travailler avec Symfony et API Platform.

Commentaires

Ajouter un commentaire

Votre commentaire sera modéré par nos administrateurs

Vous avez un projet ? Nos équipes répondent à vos questions

Contactez-nous