Contactez-nous

Projet guidé : Création d'un gestionnaire de tâches simple (sans base de données)

Apprenez à créer un gestionnaire de tâches simple avec Symfony. Ce guide pratique détaille la définition des routes, la création de contrôleurs, le développement de templates Twig et la navigation, sans base de données.

Objectif du mini-projet : Lister et afficher des tâches

Ce projet guidé a pour principal objectif de vous faire mettre en oeuvre les concepts fondamentaux de Symfony que vous avez découverts. Nous allons construire ensemble une application web très simple : un gestionnaire de tâches. Pour cette première itération, nous nous concentrerons sur deux fonctionnalités clés : afficher une liste de toutes les tâches et permettre de consulter le détail d'une tâche spécifique.

Afin de simplifier l'apprentissage et de focaliser notre attention sur le mécanisme de base de Symfony (Requête -> Route -> Contrôleur -> Template -> Réponse), nous n'utiliserons pas de base de données dans ce projet. Les données des tâches (identifiant, titre, description) seront directement codées en dur dans notre contrôleur sous forme de tableau PHP. Cette approche nous permet d'abstraire la complexité de la persistance des données pour le moment.

A l'issue de ce projet, vous aurez une meilleure compréhension pratique de la manière dont les différents composants de Symfony interagissent pour afficher des pages dynamiques. Vous serez capable de définir des routes, de créer des contrôleurs pour gérer la logique applicative, et de concevoir des templates Twig pour présenter les informations à l'utilisateur.

Etape 1 : Définir les routes nécessaires pour les tâches

La première étape cruciale dans la création de notre gestionnaire de tâches consiste à définir les chemins, ou routes, qui permettront aux utilisateurs d'accéder aux différentes fonctionnalités. Dans Symfony, une route est une association entre une URL et un contrôleur (plus précisément, une méthode d'un contrôleur) qui sera exécuté lorsque cette URL est appelée.

Nous avons besoin de deux routes distinctes :

  • Une route pour afficher la liste de toutes les tâches. Par exemple, l'URL /taches. Nous la nommerons app_task_list.
  • Une route pour afficher les détails d'une tâche spécifique. Cette route nécessitera un paramètre dynamique pour identifier la tâche, par exemple /tache/{id}, où {id} sera l'identifiant unique de la tâche. Nous la nommerons app_task_show.

Ces routes seront définies directement au-dessus des méthodes de notre futur contrôleur grâce aux attributs PHP (une évolution des annotations). Voici à quoi ressembleront ces définitions :

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class TaskController extends AbstractController
{
    // Données des tâches (en dur pour l'exemple)
    private $tasks = [
        ['id' => 1, 'title' => 'Acheter du pain', 'description' => 'Ne pas oublier la baguette tradition.'],
        ['id' => 2, 'title' => 'Répondre aux emails', 'description' => 'Traiter les emails professionnels urgents.'],
        ['id' => 3, 'title' => 'Apprendre Symfony', 'description' => 'Suivre le cours CertiQuizz avec attention.'],
    ];

    #[Route('/taches', name: 'app_task_list', methods: ['GET'])]
    public function index(): Response
    {
        // Logique pour lister les tâches (voir étape 2)
        return new Response('Liste des tâches'); // Placeholder
    }

    #[Route('/tache/{id}', name: 'app_task_show', methods: ['GET'], requirements: ['id' => '\d+'])]
    public function show(int $id): Response
    {
        // Logique pour afficher une tâche (voir étape 2)
        return new Response('Détail de la tâche ' . $id); // Placeholder
    }
}

Notez l'utilisation de name pour donner un nom unique à chaque route, ce qui facilitera la génération d'URLs plus tard. Pour la route app_task_show, {id} est un paramètre de route. La contrainte requirements: ['id' => '\d+'] assure que l'id est bien un nombre entier. Vous pouvez vérifier vos routes avec la commande php bin/console debug:router.

Etape 2 : Créer le contrôleur et implémenter la logique

Avec nos routes définies, l'étape suivante est de créer le contrôleur qui contiendra la logique pour gérer les requêtes associées. Si vous ne l'avez pas déjà fait, vous pouvez générer un nouveau contrôleur nommé TaskController avec la commande Symfony CLI :

php bin/console make:controller TaskController

Cela créera un fichier src/Controller/TaskController.php. Nous allons y implémenter les méthodes index() pour lister les tâches et show() pour afficher le détail d'une tâche, en utilisant les données que nous allons coder en dur.

Pour la méthode index(), nous allons simplement passer notre tableau de tâches au template Twig. Pour la méthode show(int $id), nous rechercherons la tâche correspondante dans notre tableau. Si la tâche n'est pas trouvée, nous lèverons une exception NotFoundHttpException, que Symfony transformera en une page d'erreur 404.

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class TaskController extends AbstractController
{
    private array $tasks = [
        ['id' => 1, 'title' => 'Acheter du pain', 'description' => 'Ne pas oublier la baguette tradition.', 'completed' => false],
        ['id' => 2, 'title' => 'Répondre aux emails', 'description' => 'Traiter les emails professionnels urgents.', 'completed' => true],
        ['id' => 3, 'title' => 'Apprendre Symfony', 'description' => 'Suivre le cours CertiQuizz avec attention.', 'completed' => false],
    ];

    #[Route('/taches', name: 'app_task_list', methods: ['GET'])]
    public function index(): Response
    {
        return $this->render('task/index.html.twig', [
            'tasks' => $this->tasks,
        ]);
    }

    #[Route('/tache/{id}', name: 'app_task_show', methods: ['GET'], requirements: ['id' => '\d+'])]
    public function show(int $id): Response
    {
        $task = null;
        foreach ($this->tasks as $t) {
            if ($t['id'] === $id) {
                $task = $t;
                break;
            }
        }

        if (!$task) {
            throw $this->createNotFoundException('La tâche demandée n\'existe pas.');
        }

        return $this->render('task/show.html.twig', [
            'task' => $task,
        ]);
    }
}

La méthode $this->render() est un raccourci fourni par AbstractController pour rendre un template Twig et retourner un objet Response. Le premier argument est le chemin vers le fichier template (que nous créerons à l'étape suivante), et le second argument est un tableau associatif des variables à passer au template.

Etape 3 : Développer les templates Twig pour l'affichage

Maintenant que notre contrôleur prépare les données, il nous faut créer les templates Twig pour les afficher. Créez un dossier task dans votre répertoire templates/. Nous y ajouterons deux fichiers : index.html.twig pour la liste des tâches et show.html.twig pour le détail d'une tâche.

Commençons par templates/task/index.html.twig. Ce template recevra la variable tasks (un tableau de tâches) de notre contrôleur. Nous allons l'utiliser pour afficher chaque tâche et un lien vers sa page de détail :

{# templates/task/index.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}Liste des tâches{% endblock %}

{% block body %}
    <h1>Liste des tâches</h1>

    {% if tasks is not empty %}
        <ul>
            {% for task in tasks %}
                <li>
                    <a href="{{ path('app_task_show', {id: task.id}) }}">
                        {{ task.title }}
                    </a>
                    {% if task.completed %} (Terminée) {% else %} (En cours) {% endif %}
                </li>
            {% endfor %}
        </ul>
    {% else %}
        <p>Aucune tâche pour le moment.</p>
    {% endif %}

    <!-- Nous ajouterons un lien pour créer une tâche plus tard -->
{% endblock %}

Ensuite, créons templates/task/show.html.twig. Ce template recevra une variable task (un tableau associatif contenant les détails d'une tâche) :

{# templates/task/show.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}Détail : {{ task.title }}{% endblock %}

{% block body %}
    <h1>{{ task.title }}</h1>

    <p><strong>Description :</strong> {{ task.description }}</p>
    <p><strong>Statut :</strong> {% if task.completed %}Terminée{% else %}En cours{% endif %}</p>

    <p>
        <a href="{{ path('app_task_list') }}">Retour à la liste des tâches</a>
    </p>
{% endblock %}

Ces templates étendent un fichier base.html.twig qui devrait exister à la racine de templates/. Il contient la structure HTML commune à toutes les pages (, , , etc.). La fonction Twig path() est utilisée pour générer les URLs à partir des noms de route, ce qui est une bonne pratique.

Etape 4 : Ajouter des liens de navigation entre les pages

Une bonne navigation est essentielle pour toute application web. Dans notre mini-projet, nous avons déjà commencé à intégrer la navigation en utilisant la fonction Twig path() dans nos templates. Cette fonction est extrêmement utile car elle permet de générer des URLs dynamiquement en se basant sur le nom des routes que nous avons définies.

Dans templates/task/index.html.twig, chaque titre de tâche est un lien pointant vers la page de détail de cette tâche :

<a href="{{ path('app_task_show', {id: task.id}) }}">{{ task.title }}</a>

Ici, 'app_task_show' est le nom de la route pour afficher une tâche. Le second argument, {id: task.id}, fournit la valeur du paramètre id requis par cette route.

De même, dans templates/task/show.html.twig, nous avons un lien pour revenir à la liste des tâches :

<a href="{{ path('app_task_list') }}">Retour à la liste des tâches</a>

La route 'app_task_list' ne nécessite aucun paramètre. L'avantage principal de l'utilisation de path() est que si vous décidez de changer l'URL d'une route dans votre contrôleur (par exemple, de /taches à /mes-taches), vous n'aurez pas besoin de modifier manuellement tous les liens dans vos templates, tant que le nom de la route (app_task_list) reste le même.

Après avoir implémenté ces éléments, testez soigneusement votre application. Naviguez vers /taches dans votre navigateur. Vous devriez voir la liste des tâches. Cliquez sur une tâche pour afficher ses détails, puis utilisez le lien de retour pour revenir à la liste. Cela confirme que vos routes, votre contrôleur, vos templates et votre navigation fonctionnent correctement ensemble.