<-

Retour

Symfony 6: Les Contrôleurs

Symfony 6: Les Contrôleurs

Ce support de cours vous introduira aux contrôleurs dans le contexte du développement web avec le Framework Symfony.

Vous apprendrez comment créer, configurer et utiliser des contrôleurs pour interagir avec les utilisateurs, traiter les données et générer des réponses dynamiques.

0

Partager sur twitterPartager sur FacebookPartager sur LinkdinPartager sur Telegram

Plan du cours

  1. Introduction aux contrôleurs Symfony
    1. Rôle des contrôleurs
    2. Présentation de l'architecture de Symfony
    3. Avantages d'utiliser des contrôleurs dans le web
    4. Création d'un contrôleur basique
    5. Les routes dynamiques
  2. La requête
    1. Paramètre d'url
    2. Le corps de la reqête
  3. AbstractController
  4. Conclusion

Prérequis


Objectifs

  • Comprendre le rôle des contrôleurs dans le développement web avec Symfony
  • Savoir créer, configurer et utiliser des contrôleurs dans une application Symfony
  • Maîtriser les techniques avancées telles que la gestion des routes, la validation des données et l'utilisation des services dans les contrôleurs
  • Être capable de générer des réponses dynamiques à partir des contrôleurs
  • Apprendre les bonnes pratiques de développement des contrôleurs avec Symfony

1. Introduction aux contrôleurs

Dans le développement web, l'architecture Modèle-Vue-Contrôleur (MVC) est largement utilisée pour séparer les différentes responsabilités d'une application.


Le contrôleur est la partie du MVC chargée de recevoir les requêtes HTTP, d'effectuer des traitements et de renvoyer les réponses appropriées.


Representation graphique du patterne MVC dans le developpement de serveur WEB HTTP. Le Contrôleur s'occupe de traiter les données réçues, d'interagir avec le modèle pour enregistrer ou recuperer des données de la base de données, et construit une réponse en utilisant les moteur de template avant de l'envoyer au client.

1.1. Présentation de l'architecture

Dans le contexte de Symfony, une application est structurée en différents composants, notamment les contrôleurs, les vues et les modèles.


Symfony s'occupe automatiquement du Routing, et associe chaque route à une action spécifique que vous aurez définit.


Les contrôleurs agissent comme des intermédiaires entre les routes (URL) et les actions à effectuer.


Representation graphique du fonctionnement d'un contrôleur avec Symfony 6. Le Kernel est reponsable du Routing, et execute l'action associé à la route et à la ma ethode de la reupete HTTP reçue. Le contrôleur est composé d'action associé à des route qui seront éxécutées par le Kernel.

Ils récupèrent les informations de la requête, traitent les données via les modèles et génèrent des réponses pour les afficher aux utilisateurs.


1.2. Avantages d'utiliser des contrôleurs

L'utilisation de contrôleurs présente plusieurs avantages, tels que la séparation claire des responsabilités, la réutilisabilité du code, la facilité de maintenance et la gestion efficace des requêtes et des réponses.


2. Création de Contrôleur

2.1. Contrôleur de base

Pour créer un nouveau contrôleur dans Symfony, suivez ces étapes :


  1. Naviguez vers le répertoire src/Controller de votre projet Symfony.
  2. Créez un nouveau fichier PHP pour votre contrôleur, par exemple AccueilController.php.
  3. Ajoutez le namespace App\Controller pour que Symfony puisse reconnaître votre contrôleur et le charger.
  4. Déclarez la classe AccueilController (Le nom de la classe doit être impérativement le même que le nom du fichier).

Voici un exemple de code pour la création d'un contrôleur de base :


// 2. src/Controller/AccueilController.php

// 3. Ajouter le namesapce
namespace App\Controller;

// 4. Définir la classe (Meme nom que le ficher!)
class AccueilController
{
    // Vos actions seront définies ici.

}


2.2. Les routes

Dans Symfony, les routes sont associées à des actions (méthodes) de notre classe contrôleur.


Symfony propose plusieurs méthodes pour configurer les routes : l'utilisation des annotations, l'utilisation d'un fichier de configuration YAML ou XML, etc...


Nous allons utiliser la dernière méthode ajoutée à Symfony 6, les Attributes avec la classe Route de Symfony.


La classe Route prends plusieurs arguments optionnels pour la configurer, mais elle doit toujours avoir:


  • url: L'url à associer à la méthode/action executée.
  • name: Le nom de la route, doit être unique.

  #[Route("/URL", name:"nom.route")]

Voici un exemple pour définir une route associée a l'URL / nommée acceuil et acceptant les requête avec les méthodes GET et HEAD:


// src/Controller/AccueilController.php

// ...

use Symfony\Component\Routing\Annotation\Route;

class AccueilController
{ 
    // Route correspendant a l'url '/' nommée accueil, acceptant les méthodes HTTP GET et HEAD
    #[Route("/", name:"accueil", methods:['GET','HEAD'])]
}

Vous trouverez ici la documentation complète des paramètres optionnels de la classe Route sur le site officiel de Symfony


2.3. Les actions

Les actions sont les méthodes exécutées quand une requête est reçue sur l'URL indiquée par la Route qui la précède.


Pour être valide, une action doit toujours retourner un objet de type Response représentant la réponse envoyée au client une fois le traitement terminé.


Elle est importée depuis Symfony et prend trois paramètres :


  • content : Une chaîne de caractères représentant le contenu à envoyer au client, cela peut être du texte, du JSON ou du HTML par exemple.
  • status : Un entier pour indiquer le statut de la réponse HTTP, sa valeur est de 200 par défaut.
  • headers : Un tableau pour ajouter des en-têtes à vos réponses HTTP.

<?php
// src/Controller/AccueilController.php

namespace App\Controller;

// Importer la classe pour les Route de Symfony
use Symfony\Component\Routing\Annotation\Route;

// Importer la classe Response de Symfony
use Symfony\Component\HttpFoundation\Response;

class AccueilController
{
    #[Route("/", name:"accueil")]
    
    // Action a executé quand une requête est reçcu sur l'url '/'
    public function index(): Response
    {
        // Retourner un objet de type Response
        return new Response(
          '<h1>Salut tout le monde!</h1>', // Le contenu
          Response::HTTP_OK, // Le status (200)
          ['content-type' => 'text/html'] // Les en-têtes
        );
    }
}


Vous pouvez aussi retourner une réponse en JSON en utilisant la classe JsonResponse, qui hérite de la classe Response :


// src/Controller/AccueilController.php

namespace App\Controller;

// Importer la classe permettant créer une réponse en json
use Symfony\Component\HttpFoundation\JsonResponse;

class AccueilController
{
    #[Route("/", name:"accueil")]
    public function index(): Response
    {
        return new JsonResponse(
          ['message'=>'Bonjour tout le monde!'],
          Response::HTTP_OK,
          ['content-type' => 'application/json']
        );
    }
}


2.4. Les routes dynamiques

Dans Symfony, vous pouvez définir des routes dynamiques en utilisant des parties de l'URL.


Vous pouvez utiliser des accolades {} pour indiquer un paramètre variable dans une partie de l'URL.


// src/Controller/FilmController.php

// Code précédent ...

// Route associé aux urls: '/salut/John' ou '/salut/Jane' etc...
#[Route("/salut/{nom}", name:"accueil.salut")]

// Le paramètre de la route est passé à la méthodes en argument
public function salutNom($nom): Response
{
  return new JsonResponse(
    ['message'=>'Salut ' . $nom . '!'],
    Response::HTTP_OK,
    ['content-type'=>'application/json']
  );
}

Dans cet exemple, nous avons défini une route dynamique /salut/{nom} en utilisant la syntaxe {nom} pour indiquer un paramètre variable.


La méthode sera exécutée quand une requête est reçue sur /salut/John ou /salut/Jane, par exemple.


Le paramètre nom sera extrait de l'URL et passé en tant qu'argument à la méthode salutNom.


Si vous effectuez une requête GET vers /salut/John, Symfony extraira la valeur John du segment d'URL correspondant au paramètre nom et la passera en tant qu'argument à la méthode salutNom.



Vous pouvez également spécifier des contraintes sur les paramètres des routes dynamiques en utilisant des expressions régulières.


Par exemple, vous pouvez définir un paramètre nombre qui doit être un nombre entier :


// src/Controller/FilmController.php

// Code précédent ...

// Route associé aux urls: '/salut/3' ou '/salut/10' mais pas '/salut/John'
#[Route("/salut/{id<\d+>}", name:"accueil.id")]
public function salutID($id): Response
{
  return new JsonResponse(
    ['message'=>'L\'identifiant reçu est ' . $id],
    Response::HTTP_OK,
    ['content-type' => 'application/json']
  );
}

La priorité des routes dans Symfony est déterminée par l'ordre dans lequel elles sont définies.


Lorsqu'une requête est reçue, Symfony parcourt les routes enregistrées dans l'ordre et utilise la première route qui correspond à l'URL de la requête.


Si vous placez la route /salut/{nom} avant la route /salut/{id<\d+>}, Symfony tentera d'utiliser la première route pour les URLs de la forme /salut/12.


Ainsi, l'action de la route /salut/{id<\d+>} ne sera jamais exécutée.


En plaçant la route /salut/{id<\d+>} avant la route /salut/{nom}, Symfony tentera d'abord de faire correspondre les URLs avec des segments numériques à cette route.


Si l'URL correspond au modèle /salut/{id<\d+>}, Symfony utilisera cette route.


Sinon, s'il n'y a pas de correspondance, Symfony continuera à chercher une correspondance avec d'autres routes, y compris la route /salut/{nom}.



3. La requête

Dans les actions, Symfony offre une injection de dépendances dynamique.


Nous pouvons injecter un objet de type Request dans notre méthode en précisant le type du paramètre Request $requete.


Symfony s'occupe automatiquement de créer et de peupler l'objet Request avec les données de la requête en cours.


L'objet Request est une composante essentielle du framework, il représente la requête HTTP entrante et contient toutes les informations pertinentes, telles que les paramètres de requête, les en-têtes, les cookies et le corps de la requête.


Vous pouvez accéder aux données de la requête à travers ses propriétés :


  • request : équivalent de $_POST, permet d'accéder au corps de la requête, cela est utile pour les requêtes POST, PUTetc., où les données sont envoyées dans le corps de la requête.
  • query : équivalent de $_GET, permet d'accéder aux paramètres d'url de requête.
  • cookies : équivalent de $_COOKIE, permet d'accéder aux cookies de la requête.
  • headers : permet d'accéder aux en-têtes de la requête.
  • files : équivalent de $_FILES.
  • server : équivalent de $_SERVER.
// src/Controller/FilmController.php

// Code précédent...
#[Route("/salut/{nom}", name:"accueil.salut")]
public function salutNom(Request $req): Response
{
  // Accéder aux données de $_POST
  $corps = $req->request;
  
  // Accéder aux paramètres de requête
  $parametres = $req->query;

  // Accéder aux cookies de la requête
  $cookies = $req->cookies;
    
  // Accéder aux en-têtes de la requête
  $entetes = $req->headers;
  
  // Accéder aux fichiers de la requête
  $fichiers = $req->files;
  
  // Accéder aux données du serveur
  $serveur = $req->server;

  return new JsonResponse(
    ['message'=>'Salut ' . $nom . '!'],
    Response::HTTP_OK,
    ['content-type' => 'application/json']
  );
}

Les propriétés request, query, cookies, etc., sont des instances de la classe InputBag.


La classe InputBag est utilisée pour stocker et manipuler les données associées à ces différentes parties d'une requête HTTP.


Voici quelques méthodes couramment utilisées de la classe InputBag :


  • get(key, default) : Cette méthode permet de récupérer la valeur associée à une clé spécifique dans le sac de données. Si la clé n'existe pas, elle renvoie la valeur par défaut spécifiée (ou null si aucune valeur par défaut n'est fournie).
  • has(key) : Cette méthode permet de vérifier si une clé spécifique existe dans le sac de données. Elle renvoie true si la clé existe et false sinon.
  • all() : Cette méthode renvoie toutes les données du sac sous forme d'un tableau associatif.
  • keys() : Cette méthode renvoie un tableau contenant toutes les clés présentes dans le sac de données.
  • set(key, value) : Cette méthode permet de définir une valeur pour une clé spécifique dans le sac de données.
  • remove(key) : Cette méthode permet de supprimer une clé et sa valeur associée du sac de données.
  • replace(data) : Cette méthode permet de remplacer toutes les données du sac par un nouveau tableau de données.
  • count() : Cette méthode renvoie le nombre d'éléments présents dans le sac de données.

Voici un exemple où nous récupérons un nombre envoyé dans les paramètres d'URL de cette manière : /add?x=1&y=2 :

<?php
// src/Controller/MathController.php

// Importer la classe pour les Route de Symfony
use Symfony\Component\Routing\Annotation\Route;

// importer la classe request pour accéder aux données des requête
use Symfony\Component\HttpFoundation\Request;

// Importer la classe Response pour construire des réponse
use Symfony\Component\HttpFoundation\Response;

// Importer la classe JsonResponse pour construire des réponse au format json
use Symfony\Component\HttpFoundation\JsonResponse;

class MathControlle {
  #[Route("/add", name: "accueil.addition")]
  public function addition(Request $req): Response {
    // Savoir si le paramètre x a été reçu
    $isX = $req->query->has('x');

    // Savoir si le paramètre y a été reçu
    $isY = $req->query->has('y');

    // Tester si x ou y n'a pas été reçu
    if (!$isX || !$isY) {
      // Retourner une réponse pour indiquer l'erreur
      return new JsonResponse(
        ['erreur' => 'Veuillez indiquer x et y!'],
        Response::HTTP_BAD_REQUEST,
        ['content-type' => 'application/json']
      );
    }

    // Accéder au paramètre x de la requête
    $parametreX = $req->query->get('x');

    // Accéder au paramètre y de la requête
    $parametreY = $req->query->get('y');

    $somme = $parametreX + $parametreY;

    return new JsonResponse(
      ['erreur' => $parametreX . ' + ' . $parametreY . ' = ' . $somme],
      Response::HTTP_OK,
      ['content-type' => 'application/json']
    );
  }
}

L'objet Request offre également plusieurs méthodes pour accéder au corps de la requête, qui contient généralement les données envoyées par le client.


  • getContent() : Cette méthode renvoie le contenu brut du corps de la requête sous forme de chaîne de caractères, utile pour savoir si des données ont été reçues ou non.
  • getPayload() : Cette méthode renvoie un objet de type InputBag. Vous pouvez utiliser les méthodes vues précédemment pour récupérer les données. Cette méthode est très utile car elle sérialise les données JSON ainsi que les données form-data.
  • get(key, default) : Cette méthode permet de récupérer une valeur spécifique du corps de la requête.

Voici un exemple où nous récupérons le nom et le prénom envoyés dans le corps de la requête :


// src/Controller/AccueilController.php

// Code précédent...

#[Route("/", name: "accueil.personne", methods: ['POST'])]
public function bonjour(Request $req): Response
{
  // Tester si le corps est vide
  if (!$req->getContent()) {
    return new JsonResponse(
      ['erreur' => 'nom et prenom non fournis!'],
      Response::HTTP_BAD_REQUEST,
      ['content-type' => 'application/json']
    );
  }

  // Récuperer le nom sinon Doe par défaut
  $prenom = $req->getPayload()->get('nom', 'Doe');

  // Récuperer les prénom, sinon John par défaut
  $nom = $req->getPayload()->get('prenom', 'John');

  return new JsonResponse(
    ['message' => 'Bonjour ' . $nom . ' ' . $prenom],
    Response::HTTP_OK,
    ['content-type' => 'application/json']
  );
}


4. AbstractController

La classe AbstractController est une classe abstraite fournie par le composant HttpFoundation de Symfony.


Elle fournit des fonctionnalités supplémentaires et utiles pour le développement de contrôleurs dans une application Symfony.


L'utilité principale de la classe AbstractController est de fournir des méthodes pratiques pour faciliter l'interaction avec les composants de Symfony, tels que l'accès aux services, la gestion des réponses HTTP, la génération des URLs et la gestion des formulaires.


En utilisant AbstractController, vous pouvez bénéficier de ces fonctionnalités sans avoir à répéter le code commun dans chaque contrôleur.


Pour utiliser la classe AbstractController, vous devez suivre les étapes suivantes :


Importez la classe AbstractController dans votre contrôleur :


use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

Puis étendez votre contrôleur à partir de AbstractController :


// src/Controller/FilmController.php

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class AccueilController extends AbstractController {
  #[Route("/", name: "accueil.personne", methods: ['GET'])]
  public function index(Request $req): Response {

    return $this->json(
      ['message' => 'Bonjour ' . $nom . '  ' . $prenom],
      Response::HTTP_OK,
    );
  }
}


Voici quelques-unes des méthodes utiles héritées de Symfony et disponibles lorsque vous étendez la classe AbstractController :

Méthodes de génération de réponses HTTP

  • render() : Cette méthode permet de rendre un template et de générer une réponse HTML.
  • redirectToRoute() : Elle permet de rediriger vers une autre route de votre application.
  • json() : Cette méthode permet de retourner une réponse JSON à partir d'un tableau ou d'un objet.

Méthodes d'accès aux services

  • getDoctrine() : Cette méthode vous donne accès au gestionnaire d'entités Doctrine (EntityManager), vous permettant de gérer vos entités et d'effectuer des opérations de base de données.
  • get() : Cette méthode vous permet d'accéder à d'autres services en utilisant leur nom. Par exemple, vous pouvez accéder au service de génération d'URL en utilisant $this->get('router').

Méthodes de gestion des formulaires

  • createForm() : Cette méthode vous permet de créer un objet formulaire en utilisant une classe de formulaire personnalisée.

Méthodes de gestion des sessions

  • getSession() : Cette méthode vous donne accès à la session en cours. Vous pouvez l'utiliser pour stocker et récupérer des valeurs spécifiques à la session de l'utilisateur.

Méthodes d'accès aux paramètres de configuration

  • getParameter() : Cette** méthode** vous permet d'accéder aux paramètres de configuration définis dans votre application Symfony. Vous pouvez y accéder en utilisant leur nom.

Méthodes de gestion des messages flash

  • addFlash() : Cette méthode permet d'ajouter un message flash, qui est un message temporaire stocké en session et généralement utilisé pour afficher des messages de confirmation ou d'erreur après une action.

Méthodes de gestion de la sécurité

  • getUser() : Cette méthode vous donne accès à l'utilisateur actuellement authentifié. Vous pouvez l'utiliser pour récupérer des informations sur l'utilisateur connecté.

Ces méthodes ne sont qu'un aperçu des fonctionnalités fournies par la classe AbstractController.


Nous les utiliserons plus en détail dans la suite de la série, mais vous pouvez consulter la documentation officielle de Symfony pour en savoir plus sur ces fonctionnalités et découvrir de nouvelles méthodes qui pourraient être pertinentes pour votre projet.



Conclusion

Nous avons appris que les contrôleurs sont responsables de la réception des requêtes HTTP et de la génération des réponses correspondantes.


Ensuite, nous avons exploré le processus de traitement d'une requête dans Symfony, en mettant l'accent sur les différentes étapes telles que la correspondance de la route, la création de l'objet Request, et la gestion des paramètres de la requête.


Nous avons ensuite abordés la classe AbstractController de Symfony, qui sert de base pour la création de contrôleurs.


Nous avons découvert que cette classe fournit une multitude de méthodes utiles pour simplifier le développement, notamment la génération de réponses HTTP, l'accès aux services, la gestion des formulaires et des sessions, entre autres.



Aller plus loin

Vous pouvez poursuivre votre apprentissage en explorant le chapitre suivant, où nous aborderons en détail l'ORM Doctrine et d'autres aspects importants du développement Symfony.


Commentaires

IsLoading