Les contrôleurs avec Symfony2

Ah, le contrôleur ! Vous le savez, c'est lui qui contient toute la logique de notre site internet. Cependant, cela ne veut pas dire qu'il contient beaucoup de code. En fait, il ne fait qu'utiliser des services, les modèles et appeler la vue. Finalement, c'est un chef d'orchestre qui se contente de faire la liaison entre tout le monde.

Nous verrons dans ce chapitre ses droits, mais aussi son devoir ultime : retourner une réponse !

Le rôle du contrôleur

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.

Mais concrètement, qu'est-ce que cela signifie, « retourner une réponse » ?

Souvenez-vous, Symfony2 s'est inspiré des concepts du protocole HTTP. Il existe dans Symfony2 une classe Response. Retourner une réponse signifie donc tout simplement : instancier un objet Response, disons $response, et faire un return $response.

Voici le contrôleur le plus simple qui soit, c'est le contrôleur qu'on avait à créer 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 ! » :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function indexAction()
  {
    return new Response("Hello World !");
  }
}

Et voilà, votre contrôleur remplit parfaitement son rôle !

Bien sûr, vous n'irez pas très loin en sachant juste cela. C'est pourquoi la suite de ce chapitre est découpée en deux parties :

  • Les objets Request et Response qui vont vous permettre de construire une réponse en fonction de la requête ;
  • Les services 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 de la requête

Heureusement, toutes les requêtes que l'on peut faire sur un site internet ne sont pas aussi simples que notre « Hello World ! ». Dans bien des cas, une requête contient des paramètres : l'id d'un article à afficher, le nom d'un membre à chercher dans la base de données, etc. Les paramètres sont la base de toute requête : la construction de la page à afficher dépend de chacun des paramètres en entrée.

Ces paramètres, nous savons déjà les gérer, nous l'avons vu dans le chapitre sur le routeur. Mais voici un petit rappel.

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 sdzblog_voir :

1
2
3
4
5
6
7
# src/Sdz/BlogBundle/Resources/config/routing.yml

sdzblog_voir:
    path:      /article/{id}
    defaults:  { _controller: SdzBlogBundle:Blog:voir }
    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 :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  // …

  public function voirAction($id)
  {
    return new Response("Affichage de l'article 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 /blog/article/5?tag=vacances, il nous faut bien un moyen pour récupérer ce paramètre tag ! C'est ici qu'intervient l'objet Request. Tout d'abord, voici comment récupérer la requête depuis un contrôleur :

1
2
<?php
$request = $this->getRequest();

Voilà, c'est aussi simple que cela ! Maintenant que nous avons notre requête, récupérons nos paramètres :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  // …

  public function voirAction($id)
  {
    // On récupère la requête
    $request = $this->getRequest();

    // On récupère notre paramètre tag
    $tag = $request->query->get('tag');

    return new Response("Affichage de l'article d'id : ".$id.", avec le tag : ".$tag);
  }
}

Et vous n'avez plus qu'à tester le résultat : /blog/article/9?tag=vacances.

Nous avons utilisé <?php $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

<?php $request->query

\$_GET

<?php $request->query->get('tag')

Variables de formulaire

<?php $request->request

\$_POST

<?php $request->request->get('tag')

Variables de cookie

<?php $request->cookies

\$_COOKIE

<?php $request->cookies->get('tag')

Variables de serveur

<?php $request->server

\$_SERVER

<?php $request->server->get('REQUEST_URI')

Variables d'entête

<?php $request->headers

\$SERVER['HTTP*']

<?php $request->headers->get('USER_AGENT')

Paramètres de route

<?php $request->attributes

n/a

<?php $request->attributes->get('id') Est équivalent à : <?php $id

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 <?php $request->getMethod() ?> :

1
2
3
4
5
<?php
if( $request->getMethod() == '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 !

1
2
3
4
5
<?php
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 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) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  // On modifie voirAction, car elle existe déjà
  public function voirAction($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
    // Rappelez-vous, 404 correspond à « page introuvable »
    $response->setStatusCode(404);

    // On retourne la réponse
    return $response;
  }
}

N'hésitez pas à tester cette page, l'URL est http://localhost/Symfony/web/app_dev.php/blog/article/5 si vous avez gardé les mêmes routes depuis le début.

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, dans un template. Heureusement pour nous, le contrôleur dispose d'un raccourci : la méthode <?php $this->render(). 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 :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Nous n'avons plus besoin du use pour l'objet Response
// use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function voirAction($id)
  {
    // On utilise le raccourci : il crée un objet Response
    // Et lui donne comme contenu le contenu du template
    return $this->render('SdzBlogBundle:Blog:voir.html.twig', array(
      'id'  => $id,
    ));
  }
}

Et voilà, en une seule ligne, c'est bouclé ! 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.

N'oubliez pas de créer la vue associée bien entendu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{# src/Sdz/BlogBundle/Resources/view/Blog/voir.html.twig #}

<!DOCTYPE html>
<html>
  <head>
    <title>Lecture de l'article {{ id }}</title>
  </head>
  <body>
    <h1>Hello Article n°{{ id }} !</h1>
  </body>
</html>

Si vous ne deviez retenir qu'une seule chose de cette section, c'est bien cette méthode <?php $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 faire cela, il existe également un raccourci du contrôleur : la méthode <?php $this->redirect(). Elle prend en paramètre l'URL vers laquelle vous souhaitez faire la redirection et s'occupe de créer une réponse, puis d'y définir un header qui contiendra votre URL. En action, cela donne le code suivant :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
  public function voirAction($id)
  {
    // On utilise la méthode « generateUrl() » pour obtenir l'URL de la liste des articles à la page 2
    // Par exemple
    return $this->redirect( $this->generateUrl('sdzblog_accueil', array('page' => 2)) );
  }
}

Essayez d'aller à l'adresse http://localhost/Symfony/web/app_dev.php/blog/article/5 et vous serez redirigés vers l'accueil !

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 :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function voirAction($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 que l'on renvoie du JSON et non du HTML
    $response->headers->set('Content-Type', 'application/json');

    return $response;

    // Nous n'avons pas utilisé notre template ici, car il n'y en a pas vraiment besoin
  }
}

Testez le rendu en allant sur http://localhost/Symfony/web/app_dev.php/blog/article/5.

Les différents services

Qu'est-ce qu'un service ?

Je vous en ai déjà brièvement parlé : un service est un script qui remplit un rôle précis et que l'on peut utiliser depuis notre contrôleur.

Imaginez par exemple un service qui a pour but d'envoyer des e-mails. Depuis notre contrôleur, on appelle ce service, on lui donne les informations nécessaires (contenu de l'e-mail, destinataire, etc.), puis on lui dit d'envoyer l'e-mail. Ainsi, toute la logique « création et envoi d'e-mail » se trouve dans ce service et non dans notre contrôleur. Cela nous permet de réutiliser ce service très facilement ! En effet, si vous codez en dur l'envoi d'e-mail dans un contrôleur A et que, plus tard, vous avez envie d'envoyer un autre e-mail depuis un contrôleur B, comment réutiliser ce que vous avez déjà fait ? C'est impossible et c'est exactement pour cela que les services existent.

Il existe un chapitre sur les services plus loin dans ce tutoriel. N'allez pas le lire maintenant, car il demande des notions que vous n'avez pas encore. Patience, sachez juste que c'est un point incontournable de Symfony2 et que nous le traiterons bien plus en détail par la suite. ;)

Accéder aux services

Pour accéder aux services depuis votre contrôleur, il faut utiliser la méthode <?php $this->get() du contrôleur. Par exemple, le service pour envoyer des e-mails se nomme justement « mailer ». Pour employer ce service, nous faisons donc :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function voirAction($id)
  {
    // Récupération du service
    $mailer = $this->get('mailer');

    // Création de l'e-mail : le service mailer utilise SwiftMailer, donc nous créons une instance de Swift_Message
    $message = \Swift_Message::newInstance()
      ->setSubject('Hello zéro !')
      ->setFrom('tutorial@symfony2.com')
      ->setTo('votre@email.com')
      ->setBody('Coucou, voici un email que vous venez de recevoir !');

    // Retour au service mailer, nous utilisons sa méthode « send() » pour envoyer notre $message
    $mailer->send($message);

    // N'oublions pas de retourner une réponse, par exemple une page qui afficherait « L'e-mail a bien été envoyé »
    return new Response('Email bien envoyé');
  }
}

Pour que l'envoi d'e-mail fonctionne, n'oubliez pas de configurer vos paramètres si ce n'est pas déjà fait. Ouvrez le fichier app/config/parameters.yml pour modifier les paramètres mailer_*. Si vous voulez utiliser votre compte Gmail :

1
2
3
4
5
6
# app/config/parameters.yml

    mailer_transport:  gmail
    mailer_host:       
    mailer_user:       vous@gmail.com
    mailer_password:   mdp

Et si vous voulez utiliser un serveur SMTP classique :

1
2
3
4
5
6
# app/config/parameters.yml

    mailer_transport:  smtp
    mailer_host:       smtp.votre-serveur.fr
    mailer_user:       identifiant
    mailer_password:   mdp

Chargez la page /blog/article/5, et allez lire votre e-mail !

Retenez donc la méthode <?php $this->get('nom_du_service') !

Brève liste des services

Maintenant que vous savez récupérer des services, encore faut-il connaître leur nom ! Et savoir les utiliser ! Ci-après est dressée une courte liste de quelques services utiles.

Templating

Templating est un service qui vous permet de gérer vos templates (vos vues, vous l'aurez compris). En fait, vous avez déjà utilisé ce service… via le raccourci <?php $this->render ! Voici la version longue d'un <?php $this->render('MonTemplate') :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
// …
public function voirAction($id)
{
  // Récupération du service
  $templating = $this->get('templating');

  // On récupère le contenu de notre template
  $contenu = $templating->render('SdzBlogBundle:Blog:voir.html.twig');

  // On crée une réponse avec ce contenu et on la retourne
  return new Response($contenu);
}

Le service Templating est utile, par exemple, pour notre e-mail de tout à l'heure. Nous avons écrit le contenu de l'e-mail en dur, ce qui n'est pas bien, évidemment. Nous devrions avoir un template pour cela. Et pour en récupérer le contenu, nous utilisons <?php $templating->render(). ;)

Une autre fonction de ce service qui peut servir, c'est <?php $templating->exists('SdzBlogBundle:Blog:inexistant') qui permet de vérifier si « SdzBlogBundle:Blog:inexistant » existe ou non.

Request

Eh oui, encore elle. C'est également un service ! Tout à l'heure on l'a récupéré via $this->getRequest(), mais on aurait également pu la récupérer de cette façon : <?php $this->get('request'). En fait, la première méthode n'est qu'un raccourci vers la deuxième.

Session

Les outils de session sont également intégrés dans un service. Vous pouvez le récupérer via <?php $this->get('session'). Pour définir et récupérer des variables en session, il faut utiliser les méthodes get() et set(), tout simplement :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function voirAction($id)
  {
    // Récupération du service
    $session = $this->get('session');

    // On récupère le contenu de la variable user_id
    $user_id = $session->get('user_id');

    // On définit une nouvelle valeur pour cette variable user_id
    $session->set('user_id', 91);

    // On n'oublie pas de renvoyer une réponse
    return new Response('Désolé je suis une page de test, je n\'ai rien à dire');
  }
}

Pour connaître les variables de la session courante, allez dans le Profiler (la barre d'outils en bas), rubrique Request, puis descendez tout en bas au paragraphe « Session Attributes ». Très utile pour savoir si vous avez bien les variables de session que vous attendez. ;)

La session se lance automatiquement dès que vous vous en servez. Voyez par exemple à la figure suivante ce que le Profiler me dit sur une page où je n'utilise pas la session.

On constate qu'il n'y a pas d'attribut dans la session

Et voici le Profiler après que nous avons défini la variable user_id en session, à la figure suivante.

Ici, on constate que l'attribut user_id est bien défini, avec comme valeur 91

Le Profiler nous donne même les informations sur la date de création de la session, etc.

Un autre outil très pratique du service de session est ce que l'on appelle les « messages flash ». Un terme précis pour désigner en réalité une variable de session qui ne dure que le temps d'une seule page. C'est une astuce utilisée pour les formulaires par exemple : la page qui traite le formulaire définit un message flash (« Article bien enregistré » par exemple) puis redirige vers la page de visualisation de l'article nouvellement créé. Sur cette page, le message flash s'affiche, et est détruit de la session. Alors si l'on change de page ou qu'on l'actualise, le message flash ne sera plus présent. Voici un exemple d'utilisation (dans la méthode ajouterAction()) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class BlogController extends Controller
{
  public function voirAction($id)
  {
    return $this->render('SdzBlogBundle:Blog:voir.html.twig', array(
      'id'  => $id
    ));
  }

  // Ajoutez cette méthode ajouterAction :
  public function ajouterAction()
  {
    // Bien sûr, cette méthode devra réellement ajouter l'article
    // Mais faisons comme si c'était le cas
    $this->get('session')->getFlashBag()->add('info', 'Article bien enregistré');

    // Le « flashBag » est ce qui contient les messages flash dans la session
    // Il peut bien sûr contenir plusieurs messages :
    $this->get('session')->getFlashBag()->add('info', 'Oui oui, il est bien enregistré !');

    // Puis on redirige vers la page de visualisation de cet article
    return $this->redirect( $this->generateUrl('sdzblog_voir', array('id' => 5)) );
  }
}

Vous pouvez voir que la méthode ajouterAction définit deux messages flash (appelés ici « info »). La lecture de ces messages se fait dans la vue de l'action voirAction, que j'ai modifiée comme ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{# src/Sdz/BlogBundle/Resources/views/Blog/voir.html.twig #}

<!DOCTYPE html>
<html>
  <head>
    <title>Bienvenue sur ma première page avec le Site du Zéro !</title>
  </head>
  <body>
    <h1>Lecture d'un article</h1>

    <p>
      {# On affiche tous les messages flash dont le nom est « info » #}
      {% for message in app.session.flashbag.get('info') %}
        <p>{{ message }}</p>
      {% endfor %}
    </p>

    <p>
      Ici nous pourrons lire l'article ayant comme id : {{ id }}<br />
      Mais pour l'instant, nous ne savons pas encore le faire, cela viendra !
    </p>
  </body>
</html>

La variable Twig {{ app }} est une variable globale, disponible partout dans vos vues. Elle contient quelques variables utiles, nous le verrons, dont le service « session » que nous venons d'utiliser via {{ app.session }}.

Essayez d'aller sur http://localhost/Symfony/web/app_dev.php/blog/ajouter, vous allez être redirigés et voir le message flash. Faites F5, et hop ! il a disparu.

Sachez également que le service « session » est aussi accessible depuis le service « request ». Ainsi, depuis un contrôleur vous pouvez faire :

1
2
<?php
$session = $this->getRequest()->getSession();

Les autres… et les nôtres !

Il existe évidemment bien d'autres services : nous les rencontrerons au fur et à mesure dans ce cours.

Mais il existera surtout nos propres services ! En effet, la plupart des outils que nous allons créer (un formulaire, un gestionnaire d'utilisateurs personnalisé, etc.) devront être utilisés plusieurs fois. Quoi de mieux, dans ce cas, que de les définir en tant que services ? Nous verrons cela dans la partie 4, mais sachez qu'après une petite étape de mise en place (configuration, quelques conventions), les services sont vraiment très pratiques !

Application : le contrôleur de notre blog

Construction du contrôleur

Notre blog est un bundle plutôt simple. On va mettre toutes nos actions dans un seul contrôleur « Blog ». Plus tard, nous pourrons éventuellement créer un contrôleur « Tag » pour manipuler les tags.

Malheureusement, on ne connaît pas encore tous les services indispensables. À ce point du cours, on ne sait pas réaliser de formulaire, manipuler les articles dans la base de données, ni même créer de vrais templates.

Pour l'heure, notre contrôleur sera donc très simple. On va créer la base de toutes les actions que l'on a mises dans nos routes. Je vous remets sous les yeux nos routes, et on enchaîne sur le contrôleur :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# src/Sdz/BlogBundle/Resources/config/routing.yml

sdzblog_accueil:
    path:      /{page}
    defaults:  { _controller: SdzBlogBundle:Blog:index, page: 1 }
    requirements:
        page:  \d*

sdzblog_voir:
    path:      /article/{id}
    defaults:  { _controller: SdzBlogBundle:Blog:voir }
    requirements:
        id:  \d+

sdzblog_ajouter:
    path:      /ajouter
    defaults:  { _controller: SdzBlogBundle:Blog:ajouter }

sdzblog_modifier:
    path:      /modifier/{id}
    defaults:  { _controller: SdzBlogBundle:Blog:modifier }
    requirements:
        id:  \d+

sdzblog_supprimer:
    path:      /supprimer/{id}
    defaults:  { _controller: SdzBlogBundle:Blog:supprimer }
    requirements:
        id:  \d+

Et le contrôleur « Blog » :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?php
// src/Sdz/BlogBundle/Controller/BlogController.php

namespace Sdz\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Httpfoundation\Response;

class BlogController extends Controller
{
  public function indexAction($page)
  {
    // On ne sait pas combien de pages il y a
    // Mais on sait qu'une page doit être supérieure ou égale à 1
    if( $page < 1 )
    {
      // On déclenche une exception NotFoundHttpException
      // Cela va afficher la page d'erreur 404 (on pourra personnaliser cette page plus tard d'ailleurs)
      throw $this->createNotFoundException('Page inexistante (page = '.$page.')');
    }

    // Ici, on récupérera la liste des articles, puis on la passera au template

    // Mais pour l'instant, on ne fait qu'appeler le template
    return $this->render('SdzBlogBundle:Blog:index.html.twig');
  }


  public function voirAction($id)
  {
    // Ici, on récupérera l'article correspondant à l'id $id

    return $this->render('SdzBlogBundle:Blog:voir.html.twig', array(
      'id' => $id
    ));
  }

  public function ajouterAction()
  {
    // La gestion d'un formulaire est particulière, mais l'idée est la suivante :

    if( $this->get('request')->getMethod() == 'POST' )
    {
      // Ici, on s'occupera de la création et de la gestion du formulaire

      $this->get('session')->getFlashBag()->add('notice', 'Article bien enregistré');

      // Puis on redirige vers la page de visualisation de cet article
      return $this->redirect( $this->generateUrl('sdzblog_voir', array('id' => 5)) );
    }

    // Si on n'est pas en POST, alors on affiche le formulaire
    return $this->render('SdzBlogBundle:Blog:ajouter.html.twig');
  }

  public function modifierAction($id)
  {
    // Ici, on récupérera l'article correspondant à $id

    // Ici, on s'occupera de la création et de la gestion du formulaire

    return $this->render('SdzBlogBundle:Blog:modifier.html.twig');
  }

  public function supprimerAction($id)
  {
    // Ici, on récupérera l'article correspondant à $id

    // Ici, on gérera la suppression de l'article en question

    return $this->render('SdzBlogBundle:Blog:supprimer.html.twig');
  }
}

À retenir

L'erreur 404

Je vous ai donné un exemple qui vous montre comment déclencher une erreur 404. C'est quelque chose que l'on fera souvent, par exemple dès qu'un article n'existera pas, qu'un argument ne sera pas bon (page = 0), etc. Lorsque l'on déclenche cette exception, le noyau l'attrape et génère une belle page d'erreur 404. Vous pouvez aller voir l'annexe « Comment personnaliser ses pages d'erreur ».

La définition des méthodes

Nos méthodes vont être appelées par le noyau : elles doivent donc respecter le nom et les arguments que nous avons définis dans nos routes et se trouver dans le scope « public ». Vous pouvez bien entendu rajouter d'autres méthodes, par exemple pour exécuter une fonction que vous réutiliserez dans deux actions différentes. Dans ce cas, vous ne devez pas les suffixer de « Action » (afin de ne pas confondre).

Testons-le

Naturellement, seules les actions index et voir vont fonctionner, car nous n'avons pas créé les templates associés (ce sera fait dans le prochain chapitre). Cependant, nous pouvons voir le type d'erreur que Symfony2 nous génère. Allez sur la page de suppression d'un article, à l'adresse http://localhost/Symfony/web/app_dev.php/blog/supprimer/5. Vous pouvez voir que l'erreur est très explicite et nous permet de voir directement ce qui ne va pas. On a même les logs en dessous de l'erreur : on peut voir tout ce qui a fonctionné avant que l'erreur ne se déclenche. Notez par exemple le log n°4 :

1
Matched route "sdzblog_supprimer" (parameters: "_controller": "Sdz\BlogBundle\Controller\BlogController::supprimerAction", "id": "5", "_route": "sdzblog_supprimer")

On voit que c'est bien la bonne route qui est utilisée, super ! On voit aussi que le paramètre id est bien défini à 5 : re-super !

On peut également tester notre erreur 404 générée manuellement lorsque ce paramètre page est à 0. Allez sur http://localhost/Symfony/web/app_dev.php/blog/0, et admirez notre erreur. Regardez entre autres la toolbar (voir figure suivante).

La page n'existe pas, une erreur 404 est renvoyée

Très pratique pour vérifier que tout est comme on l'attend !

Pour conclure

Créer un contrôleur à ce stade du cours n'est pas évident, car vous ne connaissez et ne maîtrisez pas encore tous les services nécessaires. Seulement, vous avez pu comprendre son rôle et voir un exemple concret.

Rassurez-vous, dans la partie 4 du tutoriel, on apprendra tout le nécessaire pour construire l'intérieur de nos contrôleurs. ;) En attendant, rendez-vous au prochain chapitre pour en apprendre plus sur les templates.

Pour plus d'informations concernant les contrôleurs, n'hésitez pas à lire la documentation officielle.


En résumé

  • Le rôle du contrôleur est de retourner un objet Response : ceci est obligatoire !
  • Le contrôleur construit la réponse en fonction des données qu'il a en entrée : paramètre de route et objet Request.
  • Le contrôleur se sert de tout ce dont il a besoin pour construire la réponse : la base de données, les vues, les différents services, etc.