• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 28/11/2019

Réalisez votre première page

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Comment Symfony retourne une réponse à l’utilisateur ?

 
Nous l'avons vu en introduction, Symfony est un framework basé sur le processus HTTP requête/réponse. Mais comment cela fonctionne-t-il ? Ensemble, nous allons reprendre ce paradigme fondamental du web et voir comment il est intégré par le framework.

Requêtes et réponses (HTTP)

Un utilisateur envoie une requête au serveur...

HTTP veut dire protocole de transfert hypertexte. C'est un ensemble de règles qui permettent à 2 machines de communiquer sur le réseau internet. Le schéma suivant explique ce qu'il se passe au niveau du réseau quand un utilisateur accède à un lien à l'aide d'un navigateur web :

Une requête HTTP arrive sur le serveur
Une requête HTTP arrive sur le serveur

Bien que cela semble compliqué, c'est en réalité très simple : le rôle d'un serveur web est toujours de retourner une réponse à l'utilisateur.

En "langage" HTTP, voici l'équivalent de la requête d'un utilisateur qui accéderait au site d'OpenClassrooms :

GET / HTTP/1.1
Host: openclassrooms.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh)

Cette simple requête contient l'information nécessaire pour permettre au serveur de retourner une réponse :

  • la première ligne contient la méthode HTTP (ici "GET") ainsi que l’URL (ici "/") ;

  • la deuxième ligne contient le type de contenu attendu, ici du HTML ;

  • la troisième informe le serveur du navigateur utilisé (ici, Mozilla Firefox sur Mac OSX).

Il existe plusieurs méthodes HTTP pour accéder à une ressource, voici les plus importantes : GET, POST, PUT et DELETE.

... et le serveur retourne une réponse

Une fois que le serveur sait exactement quelle ressource l'utilisateur (on dit parfois "client") souhaite et sous quelle forme, il peut retourner ce résultat sous forme de réponse HTTP, tel qu'illustré dans le schéma suivant :

Et le serveur répond par une page HTML !
Et le serveur répond par une page HTML !

Traduit en "langage" HTTP, voici l'équivalent d'une réponse retournée par un des serveurs d'OpenClassrooms :


HTTP/1.1 200 OK
Date: Sat, 28 Jul 2018 21:05:05 GMT
Server: cloudfare
Content-Type: text/html

<html>
 <!-- ... HTML de la page d'accueil d'OpenClassrooms -->
</html>

La réponse retournée à l'utilisateur est une page HTML contenant la page d'accueil d'OpenClassrooms. Sur la première ligne, une information est particulièrement importante, puisqu'elle indique le code de statut HTTP : ici 200 (OK). De très nombreux statuts existent, parmi les plus connus :

  • 200, la page a été retournée sans erreur du serveur ;

  • 404, le code HTTP pour une ressource qui n'a pas été retrouvée sur le serveur ;

  • les codes 3XX, qui signalent les redirections de ressources ;

  • les codes 4XX, qui signalent une erreur côté utilisateur/client ;

  • les codes 5XX, qui signalent une erreur côté serveur.

Manipulez la couche HTTP en PHP

Le PHP est un langage de programmation serveur pour le web, il est donc assez facile de récupérer des informations du client et de retourner une réponse. Par exemple, le code suivant récupère des informations de la requête utilisateur et retourne une réponse au format HTML :

<?php

// en utilisant l'url localhost?name=Zozor
$name = $_GET['name'];

header('Content-Type: text/html');
echo '<html>';
echo '<body>Bonjour '. $name . '</body>';
echo '</html>'

Ce "serveur" PHP retournerait la réponse HTTP suivante :

HTTP/1.1 200 OK
Date: Sat, 28 Jul 2018 02:14:33 GMT
Server: Apache/2.2.17 (Unix)
Content-Type: text/html

<html>
<body>Bonjour Zozor</body>
</html>

Ce simple programme écrit en PHP est bien capable d'agir en tant que serveur HTTP et de retourner une réponse.

Requêtes et réponses en Symfony

Le framework Symfony, et notamment son composant HttpFoundation, apporte une couche d'abstraction pour la requête et la réponse, simple à utiliser et à manipuler.

La classe Request

La classe Request permet de centraliser l'accès à toutes les super variables de PHP en une seule classe utilitaire.

<?php
use Symfony\Component\HttpFoundation\Request;

// Récupération des valeurs accessibles dans les super variables
$request = Request::createFromGlobals();

// Récupérer l'url
$request->getPathInfo();

// récupérer des attributs en GET ou POST
$request->query->get('name');
$request->request->get('name', 'nom par défaut');

$request->getMethod();    // e.g. GET, POST, PUT, DELETE ou HEAD

La classe Response

La classe Response permet de retourner une réponse à l'utilisateur valide en termes de langage HTTP.

Réécrivons l'exemple précédent avec cette classe :

<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$name = $request->get('name');
$response = new Response();

$response->setContent(
    '<html><body>Hello'
    . $name
    .'</body></html>'
);
$response->setStatusCode(Response::HTTP_OK);
$response->headers->set('Content-Type', 'text/html');

// Retourne une réponse HTTP valide
$response->send();

À ce stade, c'est déjà beaucoup plus facile à manipuler, n'est-ce pas ? 😎

Liez une URL à une action

Finalement, récupérer les informations de la requête et retourner une réponse est assez simple. La complexité d'une application web vient après, quand il va falloir appeler l'action correspondante en fonction de l’URL . Pour ce faire, nous avons besoin d'un contrôleur "front" ou frontal : il est en charge de récupérer les informations de la requête et d'exécuter l'action correspondante qui retournera une réponse.

Au plus simple, un contrôleur front pourrait être implémenté de cette façon :

<?php
// index.php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$url = $request->getPathInfo();
$response = new Response();

switch($url) {
    case '/':
        $response->setContent('Accueil');
        break;
    case '/admin':
        $response->setContent('Accès Espace Admin');
        break;
    default:
        $response->setStatusCode(Response::HTTP_NOT_FOUND);
}

$response->send();

Pour de très grosses applications, ce système semble vraiment limité. Heureusement, le framework Symfony fournit également un contrôleur frontal beaucoup plus puissant et extensible.

La gestion du "routing" dans Symfony

La responsabilité de lier une URL à une action PHP revient au composant Routing qui est disponible dans le framework. Le composant Routing est très puissant et supporte de nombreux formats de déclaration : PHP, bien sûr, mais également XML, YAML ou les annotations qui sont le format recommandé que nous utiliserons. Voici un exemple :

<?php

// src/Controller/HelloController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class HelloController extends AbstractController
{
    /**
     * Page d'accueil
     *
     * @Route("/", name="accueil")
     */
    public function home()
    {
        // ...
    }

    /**
     * Page d'accès à un article
     *
     * @Route("/article/{postId}", name="article")
     */
    public function showBlogPost($postId)
    {
        // $postId est retrouvé à partir de l'url
        // par ex /article/1234, alors $articleId = 1234

        // ...
    }
}

Ici, l'annotation Route s'utilise dans un bloc de commentaire particulier (il commence par 2 astérisques) et permet de définir les paramètres et contraintes de la route pour laquelle l'action (ici  home()  ou  showBlogPost($postId)) se déclenchera.

Le premier argument est la route en elle-même qui accepte des expressions régulières très puissantes !

Par exemple, reprenons et améliorons l'exemple précédent :

<?php

/**
 * @Route(
 *  "/article/{postId<\d+>}",
 *  name="article",
 *  methods={"GET"}
 * )
 */
public function showBlogPost($postId = 1)
{
    // ...
}

Nous venons de définir les pré-requis complémentaires suivants :

  • la valeur de $postId passé en paramètre de l’URL doit forcément être un entier supérieur ;

  • la valeur par défaut si non trouvé est 1 ;

  • et la méthode d'accès HTTP doit être GET.

Mais ce qu'il manque ici pour bien comprendre ce qu'il se passe "sous le capot", c'est comment un contrôleur Symfony va avoir accès à la requête de l'utilisateur. Car, contrairement à l'exemple utilisant PHP, les contrôleurs Symfony ne sont pas des contrôleurs frontaux, ils ne sont pas en charge d'écouter directement la requête utilisateur.

Le contrôleur front de Symfony

Pour créer un contrôleur front avec Symfony, nous devons utiliser un composant appelé HttpKernel qui utilise le composant HttpFoundation que nous venons de voir pour :

  • écouter une requête ;

  • et retourner une réponse.

Voici un exemple minimaliste de code fonctionnel pour la création d'un contrôleur frontal avec Symfony, vous pouvez jeter un œil à celui fourni dans l'application de démonstration du projet.

<?php

use Symfony\Component\HttpFoundation\Request;

require __DIR__.'/../vendor/autoload.php';

$environment = 'prod';
$debugEnabled = false;

$kernel = new AppKernel($environment, $debugEnabled);

$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

C'est parti !

En résumé

Le framework Symfony est construit autour du paradigme fondamental du web : un utilisateur fait une requête et le serveur (ici, Symfony) doit retourner une réponse.

  • Le composant HttpFoundation fournit une abstraction PHP objet pour la requête et la réponse.

  • Le composant HttpKernel a la responsabilité de récupérer la requête de l'utilisateur et de renvoyer une réponse.

Dans la très grande majorité des applications, la réponse du serveur sera différente selon l’URL à laquelle il sera accédé et fera appel à une fonction différente pour retourner un résultat.

Un contrôleur Symfony peut être une simple fonction d'une classe PHP et il est possible de configurer le routing à l'aide d'annotations PHP même si d'autres formats de déclaration sont possibles.

Le framework Symfony non seulement a un composant pour gérer le routing, mais fournit aussi un contrôleur frontal en charge de recevoir toutes les requêtes de l'utilisateur et de trouver la bonne action (fonction) du contrôleur à exécuter.

Dans le prochain chapitre, nous allons explorer deux autres composants fondamentaux du framework Symfony : DependencyInjection et EventDispatcher qui vont nous aider à développer des applications plus robustes, plus flexibles et plus faciles à maintenir. À tout de suite !

Exemple de certificat de réussite
Exemple de certificat de réussite