Retourner une réponse
Je vous l'ai dit de nombreuses fois depuis le début de ce cours : le rôle du contrôleur est de retourner une réponse.
Voici le contrôleur le plus simple qui soit, c'est le contrôleur qu'on
avait créé dans un des chapitres précédents. Il dispose d'une seule
méthode, nommée « index », et retourne une réponse qui ne contient que «
Hello World ! » :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function indexAction()
{
return new Response("Hello World !");
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function indexAction()
{
return new Response("Hello World !");
}
}
La suite de ce chapitre est découpée en deux parties :
- Les objets
Request
etResponse
qui vont vous permettre de construire une réponse en fonction de la requête ; - Les services de base qui vont vous permettre de réaliser tout le travail nécessaire pour préparer le contenu de votre réponse.
Manipuler l'objet Request
Les paramètres contenus dans les routes
Tout d'abord côté route, souvenez-vous, on utilisait déjà des paramètres. Prenons l'exemple de la route
oc_platform_view
:
# src/OC/PlatformBundle/Resources/config/routing.yml
oc_platform_view:
path: /advert/{id}
defaults: { _controller: OCPlatformBundle:Advert:view }
requirements:
id: \d+
oc_platform_view:
path: /advert/{id}
defaults: { _controller: OCPlatformBundle:Advert:view }
requirements:
id: \d+
Ici, le paramètre
{id}
de la requête est récupéré par la route, qui va le transformer en argument $id
pour le contrôleur. On a déjà fait la méthode correspondante dans le contrôleur, la voici pour rappel :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// …
public function viewAction($id)
{
return new Response("Affichage de l'annonce d'id : ".$id);
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// …
public function viewAction($id)
{
return new Response("Affichage de l'annonce d'id : ".$id);
}
}
Voici donc la première manière de récupérer des arguments : ceux contenus dans la route.
Les paramètres hors routes
En
plus des paramètres de routes que nous venons de voir, vous pouvez
récupérer les autres paramètres de l'URL, disons, « à l'ancienne ».
Prenons par exemple l'URL
/platform/advert/5?tag=developer
, il nous faut bien un moyen pour récupérer ce paramètre tag
! C'est ici qu'intervient l'objet Request
.
Pour
récupérer la requête depuis un contrôleur, vous devez réaliser une
petite pirouette : il faut ajouter un argument à votre méthode avec le typehint
Request
comme ceci :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; // N'oubliez pas ce use !
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id, Request $request)
{
// Vous avez accès à la requête HTTP via $request
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; // N'oubliez pas ce use !
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id, Request $request)
{
// Vous avez accès à la requête HTTP via $request
}
}
Comment est-ce
possible ? C'est en réalité le Kernel qui s'occupe de cela, car c'est
lui qui dispose de la requête. Après avoir demandé au routeur quel
contrôleur exécuter, et avant de l'exécuter effectivement, il regarde si
l'un des arguments de la méthode est typé avec
Request
. Si c'est le cas, il ajoute la requête aux arguments avant d'exécuter le contrôleur.
Maintenant que nous savons récupérer la requête, voici comment récupérer les paramètres contenus dans l'URL :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// …
// On injecte la requête dans les arguments de la méthode
public function viewAction($id, Request $request)
{
// On récupère notre paramètre tag
$tag = $request->query->get('tag');
return new Response(
"Affichage de l'annonce d'id : ".$id.", avec le tag : ".$tag
);
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// …
// On injecte la requête dans les arguments de la méthode
public function viewAction($id, Request $request)
{
// On récupère notre paramètre tag
$tag = $request->query->get('tag');
return new Response(
"Affichage de l'annonce d'id : ".$id.", avec le tag : ".$tag
);
}
}
Et vous n'avez plus qu'à tester le résultat :
/platform/advert/9?tag=developer
.
Nous avons utilisé
$request->query
pour récupérer les paramètres de l'URL passés en GET, mais vous savez qu'il existe d'autres types de paramètres :
Type de paramètres
|
Méthode Symfony2
|
Méthode traditionnelle
|
Exemple
|
---|---|---|---|
Variables d'URL
| $request->query |
$_GET
| $request->query->get('tag') |
Variables de formulaire
| $request->request |
$_POST
| $request->request->get('tag') |
Variables de cookie
| $request->cookies |
$_COOKIE
| $request->cookies->get('tag') |
Variables de serveur
| $request->server |
$_SERVER
| $request->server->get('REQUEST_URI') |
Variables d'entête
| $request->headers |
$_SERVER['HTTP_*']
| $request->headers->get('USER_AGENT') |
Paramètres de route
| $request->attributes |
n/a
|
On utilise
$id dans les arguments de la méthode |
Avec cette façon d'accéder aux paramètres, vous n'avez pas besoin de tester leur existence. Par exemple, si vous faites
$request->query->get('sdf')
alors que le paramètre sdf
n'est pas défini dans l'URL, cela vous retournera une chaîne vide, et non une erreur.
Les autres méthodes de l'objet Request
Heureusement, l'objet
Request
ne se limite pas à la récupération de paramètres. Il permet de savoir
plusieurs choses intéressantes à propos de la requête en cours, voyons
ses possibilités.Récupérer la méthode de la requête HTTP
Pour savoir si la page a été récupérée via GET (clic sur un lien) ou via POST (envoi d'un formulaire), il existe la méthode
$request->isMethod()
:
<?php
if ($request->isMethod('POST'))
{
// Un formulaire a été envoyé, on peut le traiter ici
}
if ($request->isMethod('POST'))
{
// Un formulaire a été envoyé, on peut le traiter ici
}
Savoir si la requête est une requête AJAX
Lorsque
vous utiliserez AJAX dans votre site, vous aurez sans doute besoin de
savoir, depuis le contrôleur, si la requête en cours est une requête
AJAX ou non. Par exemple, pour renvoyer du XML ou du JSON à la place du
HTML. Pour cela, rien de plus simple !
<?php
if ($request->isXmlHttpRequest())
{
// C'est une requête AJAX, retournons du JSON, par exemple
}
if ($request->isXmlHttpRequest())
{
// C'est une requête AJAX, retournons du JSON, par exemple
}
Toutes les autres
Pour avoir la liste exhaustive des méthodes disponibles sur l'objet
Request
, je vous invite à lire l'API de cet objet sur le site de Symfony2. Vous y trouverez toutes les méthodes, même si nous avons déjà survolé les principales.Manipuler l'objet Response
Décomposition de la construction d'un objet Response
Pour
que vous compreniez bien ce qu'il se passe en coulisses lors de la
création d'une réponse, voyons la manière longue et décomposée de
construire et de retourner une réponse. Pour l'exemple, traitons le cas
d'une page d'erreur 404 (page introuvable) :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// On modifie viewAction, car elle existe déjà
public function viewAction($id)
{
// On crée la réponse sans lui donner de contenu pour le moment
$response = new Response;
// On définit le contenu
$response->setContent("Ceci est une page d'erreur 404");
// On définit le code HTTP à « Not Found » (erreur 404)
$response->setStatusCode(Response::HTTP_NOT_FOUND);
// On retourne la réponse
return $response;
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
// On modifie viewAction, car elle existe déjà
public function viewAction($id)
{
// On crée la réponse sans lui donner de contenu pour le moment
$response = new Response;
// On définit le contenu
$response->setContent("Ceci est une page d'erreur 404");
// On définit le code HTTP à « Not Found » (erreur 404)
$response->setStatusCode(Response::HTTP_NOT_FOUND);
// On retourne la réponse
return $response;
}
}
Je ne vous le cache pas : nous n'utiliserons jamais cette longue méthode ! Lisez plutôt la suite.
Réponses et vues
Généralement,
vous préférerez que votre réponse soit contenue dans une vue tel que le
préconise l'architecture MVC. Heureusement pour nous, le service templating que nous avons déjà utilisé dispose d'un raccourci : la méthode
renderResponse()
.
Elle prend en paramètres le nom du template et ses variables, puis
s'occupe de tout : créer la réponse, y passer le contenu du template, et
retourner la réponse. La voici en action :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
// On utilise le raccourci : il crée un objet Response
// Et lui donne comme contenu le contenu du template
return $this->get('templating')->renderResponse(
'OCPlatformBundle:Advert:view.html.twig',
array('id' => $id)
);
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
// On utilise le raccourci : il crée un objet Response
// Et lui donne comme contenu le contenu du template
return $this->get('templating')->renderResponse(
'OCPlatformBundle:Advert:view.html.twig',
array('id' => $id)
);
}
}
Et voilà, en une seule ligne, c'est bouclé ! Et nous pouvons même aller
encore plus loin, le contrôleur lui-même dispose d'un raccourci pour
utiliser cette méthode
renderResponse
, il s'agit de la méthode render
qui s'utilise exactement de la même façon, la voici en action :
<?php
public function viewAction($id)
{
return $this->render(
'OCPlatformBundle:Advert:view.html.twig',
array('id' => $id)
);
}
public function viewAction($id)
{
return $this->render(
'OCPlatformBundle:Advert:view.html.twig',
array('id' => $id)
);
}
C'est comme cela que nous générerons la plupart de nos réponses. Finalement, l'objet
Response
est utilisé en coulisses, nous n'avons pas à le manipuler directement dans la plupart des cas.
N'oubliez pas de créer la vue associée bien entendu :
{# src/OC/PlatformBundle/Resources/view/Advert/view.html.twig #}
<!DOCTYPE html>
<html>
<head>
<title>Affichage de l'annonce {{ id }}</title>
</head>
<body>
<h1>Hello Annonce n°{{ id }} !</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Affichage de l'annonce {{ id }}</title>
</head>
<body>
<h1>Hello Annonce n°{{ id }} !</h1>
</body>
</html>
Si vous ne deviez retenir qu'une seule chose de cette section, c'est bien cette méthode
$this->render()
, car c'est vraiment ce que nous utiliserons en permanence.Réponse et redirection
Vous serez sûrement amenés à faire une redirection vers une autre page. Or notre contrôleur est obligé de retourner une réponse. Comment gérer une redirection ? Eh bien, vous avez peut-être évité le piège, mais une redirection est une réponse HTTP.
Pour simplifier la construction d'une réponse faisant une redirection, il existe l'objet RedirectResponse qui étend l'objet Response
que nous connaissons bien, en lui ajoutant les entêtes HTTP qu'il faut
pour que notre navigateur comprenne qu'il s'agit d'une redirection. Cet
objet prend en argument de son constructeur l'URL vers laquelle
rediriger, URL que vous générez grâce au routeur bien entendu.
Voyez par vous-même ce que cela donne comme code :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse; // N'oubliez pas ce use
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
$url = $this->get('router')->generate('oc_platform_home');
return new RedirectResponse($url);
}
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse; // N'oubliez pas ce use
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
$url = $this->get('router')->generate('oc_platform_home');
return new RedirectResponse($url);
}
}
Essayez d'aller à l'adresse /platform/advert/5 et vous serez redirigés vers l'accueil !
À l'image de la méthode
render
, il existe également une méthode raccourcie pour faire une redirection depuis un contrôleur, il s'agit de la méthode redirect
qui prend en argument l'URL. L'avantage est que vous n'avez pas à rajouter le use RedirectResponse
en début de fichier :
<?php
public function viewAction($id)
{
$url = $this->get('router')->generate('oc_platform_home');
return $this->redirect($url);
}
public function viewAction($id)
{
$url = $this->get('router')->generate('oc_platform_home');
return $this->redirect($url);
}
Changer le Content-type
de la réponse
Lorsque vous retournez autre chose que du HTML, il faut que vous changiez le
Content-type
de la réponse. Ce Content-type
permet au navigateur qui recevra votre réponse de savoir à quoi
s'attendre dans le contenu. Prenons l'exemple suivant : vous recevez une
requête AJAX et souhaitez retourner un tableau en JSON :
<?php
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
// Créons nous-mêmes la réponse en JSON, grâce à la fonction json_encode()
$response = new Response(json_encode(array('id' => $id)));
// Ici, nous définissons le Content-type pour dire au navigateur
// que l'on renvoie du JSON et non du HTML
$response->headers->set('Content-Type', 'application/json');
return $response;
}
// src/OC/PlatformBundle/Controller/AdvertController.php
namespace OC\PlatformBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class AdvertController extends Controller
{
public function viewAction($id)
{
// Créons nous-mêmes la réponse en JSON, grâce à la fonction json_encode()
$response = new Response(json_encode(array('id' => $id)));
// Ici, nous définissons le Content-type pour dire au navigateur
// que l'on renvoie du JSON et non du HTML
$response->headers->set('Content-Type', 'application/json');
return $response;
}
Testez le rendu en allant sur /platform/advert/5.
Commentaires
Enregistrer un commentaire