Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🐘 Symfony – Le Framework PHP Professionnel

Guide complet IDEO-Lab : Bundles, DI Container, Doctrine (ORM), Twig, Security & API Platform.

1.1 Facile

Vue d'ensemble

Framework PHP "full-stack" (ou "micro"). Basé sur des Composants.

Framework PHP
1.2 Moyen

Pourquoi Symfony ?

Robuste (entreprise), Flexible (Composants), Standard (PSR), Performance.

Composants PSR
1.3 Facile

Installation (symfony CLI)

composer (paquets), symfony (CLI). symfony new, symfony server.

Composer Symfony CLI
1.4 Facile

Structure (Flex)

/public (index.php), /src (code), /config (YAML), /var (cache).

Flex Structure
2.1 Moyen

Concept 1 : Kernel & Requête

Le "cycle de vie" (Request -> Kernel -> Controller -> Response).

Kernel Request/Response
2.2 Avancé

Concept 2 : Conteneur (DI)

services.yaml. Injection de Dépendances (DI), autowiring.

DI Container Autowiring
2.3 Moyen

Concept 3 : Bundles

Le "plugin" de Symfony. (DoctrineBundle, SecurityBundle...).

Bundles Plugins
2.4 Facile

Concept 4 : Routage

#[Route("/path")] (Attributs/Annotations) ou routes.yaml.

Routing #[Route]
3.1 Facile

Concept 5 : Contrôleur

AbstractController. render(), json(), redirect().

Controller Response
3.2 Facile

Concept 6 : Twig (Vues)

Moteur de template (templatetag openvariable ... templatetag closevariable, templatetag openblock ... templatetag endblock). extends, include.

Twig Templates
3.3 Avancé

Concept 7 : Doctrine (ORM)

Le "modèle" (DB). Entity, Repository, EntityManager.

Doctrine ORM Entity
3.4 Moyen

Concept 8 : Formulaires

FormBuilder, EntityType, Validation (Assert).

Forms Validation
4.1 Avancé

Concept 9 : Sécurité

SecurityBundle. (Authentification, Autorisation, Firewalls).

Security Firewalls
4.2 Avancé

Addon : API Platform

Wrapper "magique" (Bundle) pour créer des API REST/GraphQL (basé sur Doctrine).

API Platform API
4.3 Moyen

Addon : Messenger & Mercure

Messenger (Queues, Async) & Mercure (Push temps réel).

Messenger Mercure
4.4 Moyen

Cas d'Usage (Vitrine)

Apps "Entreprise", Backends (API), SaaS, (Drupal, Prestashop...).

Entreprise SaaS
5.1 Facile

Cheat-sheet

CLI (symfony, composer), bin/console, Workflow (Controller/Route).

cheat CLI
1.1 Vue d'ensemble : Le Framework PHP Professionnel

Symfony (créé par Fabien Potencier / SensioLabs) est un **Framework PHP** (un ensemble d'outils et de règles) conçu pour créer des applications web robustes et maintenables.

Il est "full-stack" (gère tout, de l'HTTP à la DB) mais aussi "micro" (on peut n'utiliser que les briques (Composants) dont on a besoin).

Diagramme : Symfony (Framework vs Composants)
+------------------------------------------+
| Votre Application (App)                  |
| (Ex: "E-Shop")                           |
+------------------------------------------+
      | (Utilise)
      ▼
+------------------------------------------+
| Le Framework Symfony (La "Colle")        |
| (Kernel, DI Container, Bundles)          |
+------------------------------------------+
      | (Utilise)
      ▼
+------------------------------------------+
| Les Composants Symfony (Les "Briques")   |
| (Ex: Console, HttpClient, Routing,      |
|  Yaml, Serializer, Finder...)           |
+------------------------------------------+

Des projets majeurs (comme Drupal, Prestashop, ou Laravel) n'utilisent pas le "Framework" Symfony, mais ils utilisent massivement les "Composants" Symfony.

1.2 Pourquoi Symfony ?
AvantageDescription
Robuste (Entreprise)Conçu pour le long terme (LTS), le code "propre" (Tests, DI), et la performance. (Opposé au "code spaghetti" PHP).
Flexible (Composants)Vous pouvez l'utiliser en "micro-framework" (juste le routage) ou "full-stack" (avec Twig, Doctrine, Forms...).
Standard (PSR)Symfony suit (et définit) les standards PSR (PHP Standards Recommendations). (Interopérabilité).
Injection de Dépendances(DI) Le Cœur de Symfony (voir 2.2). Force une architecture découplée (propre) via l'Autowiring.
Écosystème (Bundles)Système de "plugins" (Bundles) très riche (Doctrine, Security, API Platform...).
1.3 Installation (symfony CLI & composer)

L'installation moderne repose sur 2 outils : Composer (le "npm" de PHP) et Symfony CLI (l'outil d'aide).

1. Les Outils
# 1. Composer (Gestionnaire de paquets PHP)
# (Installer globalement, voir getcomposer.org)
composer

# 2. Symfony CLI (Binaire "Helper")
# (Installer globalement, voir symfony.com/download)
symfony
2. Création Projet
# 1. Créer un projet (via Symfony CLI)
# (Crée un squelette "full-stack" avec --webapp)
symfony new mon_projet --webapp

# 2. (Alternative: via Composer)
composer create-project symfony/skeleton:"^7.0" mon_projet

# 3. Installer un "Bundle" (via Symfony Flex)
# (Flex (via composer) gère l'installation/config auto)
cd mon_projet
composer require twig # (Ajoute le moteur de template Twig)
composer require maker --dev # (Ajoute les générateurs de code)
3. Lancement (Serveur de Dev)
# (Utiliser le binaire 'symfony' (recommandé))
# (Détecte PHP-FPM, gère Docker, etc.)
symfony server:start

# (Ouvre http://127.0.0.1:8000)
1.4 Structure (Symfony Flex)

Symfony Flex (installé par défaut) organise le projet de manière standard (orienté "domaines").

/mon_projet
  |
  +-- /bin
  |   +-- console    (Le CLI de Symfony: "php bin/console cache:clear")
  |
  +-- /config
  |   +-- routes.yaml  (Routage (ou via Attributs))
  |   +-- services.yaml(Conteneur DI (voir 2.2))
  |   +-- packages/    (Config des Bundles (ex: doctrine.yaml))
  |
  +-- /public
  |   +-- index.php    (Le "Front Controller" - Point d'entrée UNIQUE)
  |   +-- (CSS, JS, Images...)
  |
  +-- /src
  |   +-- Controller/  (Logique HTTP (Contrôleurs))
  |   +-- Entity/      (Classes PHP (Doctrine Models))
  |   +-- Repository/  (Accès DB (Doctrine Repos))
  |   +-- Form/        (Formulaires)
  |   +-- Kernel.php   (Le Cœur de l'app)
  |
  +-- /templates
  |   +-- (Fichiers Twig .html.twig)
  |
  +-- /var
  |   +-- /cache/      (Cache (compilé))
  |   +-- /log/        (Logs)
  |
  +-- .env             (Variables d'env (DATABASE_URL, ...))
  +-- composer.json    (Dépendances PHP)
2.1 Concept 1 : Kernel & Cycle de Vie (Request/Response)

Symfony est un framework "Front Controller". **Toutes** les requêtes HTTP (ex: /login, /api/users) arrivent sur **un seul fichier** : /public/index.php.

Diagramme : Cycle de vie (HTTP)
(Navigateur: GET /blog/5)
      |
      ▼
(Serveur Web: Nginx/Apache)
      | (Réécrit vers)
      ▼
+---------------------+
| /public/index.php   | (Front Controller)
+---------------------+
      | (Crée l'objet "Request")
      | (Démarre le "Kernel")
      ▼
+---------------------+
| Kernel (src/Kernel.php)|
+---------------------+
      | (Demande au "Router")
      ▼
+---------------------+
| Router (Routage)    |
| (Trouve: "BlogController::show()")
+---------------------+
      | (Appelle)
      ▼
+---------------------+
| Controller (Votre Code)
| (Ex: "BlogController.php")
| (Retourne un objet "Response")
+---------------------+
      |
      ▼
(Le Kernel envoie la "Response")
      |
      ▼
(Navigateur: Affiche le HTML)
2.2 Concept 2 : Conteneur (Injection de Dépendances - DI)

C'est le concept **le plus important** de Symfony (et le plus difficile pour un débutant PHP).

Problème (Sans DI) : Votre Contrôleur a besoin d'un "Mailer" (pour envoyer un email). Vous faites $mailer = new MailerService(). (Votre Contrôleur est "couplé" à MailerService).

Solution (Avec DI) : Vous ne créez (new) **jamais** d'objets (Services). Vous les **demandez** (dans le constructeur). Le **Conteneur de Services** (géré par config/services.yaml) les "injecte" automatiquement (Autowiring).

Exemple (services.yaml & Autowiring)
# (config/services.yaml)
# (Défaut: "autowire: true")
services:
    _defaults:
        autowire: true
        autoconfigure: true

    # (Dit à Symfony: "Tous les fichiers dans /src/ sont des 'services'")
    App\:
        resource: '../src/'
        exclude:
            - '../src/Kernel.php'
            - '../src/Entity/' # (Les Entities ne sont pas des services)

Exemple (Contrôleur)
// (src/Controller/MonController.php)
use Psr\Log\LoggerInterface;
use App\Service\MonSuperService;

class MonController extends AbstractController
{
    // 1. (Demande les "services" (objets) dans le constructeur)
    public function __construct(
        private LoggerInterface $logger,
        private MonSuperService $monService
    ) {
        // (PAS DE "new Logger()" !)
    }

    #[Route('/test')]
    public function index(): Response
    {
        // 2. (Les services sont prêts (injectés) !)
        $this->logger->info("Ceci est un log !");
        $data = $this->monService->calculerUnTruc();
        
        return $this->render('...);
    }
}
2.3 Concept 3 : Bundles (Plugins)

Un Bundle est un "plugin" (un dossier) qui ajoute des fonctionnalités (Services, Routes, Config) à Symfony.

L'architecture Symfony Flex (moderne) minimise l'utilisation des Bundles (on préfère l'autowiring simple), mais ils restent essentiels pour les "gros" add-ons.

Bundles Essentiels (Installés via composer require)
Bundle (Paquet)Rôle
symfony/framework-bundleLe "cœur" (Kernel, DI, Routing, ...).
symfony/twig-bundleAjoute le moteur de template Twig (voir 3.2).
doctrine/doctrine-bundleAjoute l'ORM Doctrine (DB) (voir 3.3).
symfony/security-bundleAjoute la gestion de la sécurité (Login, Firewalls...) (voir 4.1).
symfony/maker-bundle (Dev)Ajoute les commandes bin/console make:... (:controller, :entity).
api-platform/core (API Platform)Bundle (très complexe) pour créer des API REST/GraphQL (voir 4.2).
2.4 Concept 4 : Routage (Controller)

Le "Router" (Routeur) fait le lien entre une URL (Request) et une fonction (Controller).

Méthode moderne (recommandée) : Attributs (PHP 8+) (anciennement "Annotations") directement sur la méthode du contrôleur.

Exemple (src/Controller/BlogController.php)
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; // (PHP 8+)

class BlogController extends AbstractController
{
    // 1. Route Simple
    #[Route('/blog', name: 'blog_index')]
    public function index(): Response
    {
        // (Logique... ex: $posts = $repo->findAll())
        return $this->render('blog/index.html.twig');
    }

    // 2. Route avec Paramètre (Wildcard)
    // (Le 'slug' est injecté dans la variable $slug)
    #[Route('/blog/{slug}', name: 'blog_post_show')]
    public function show(string $slug): Response
    {
        // (Logique... ex: $post = $repo->findOneBySlug($slug))
        return $this->render('blog/show.html.twig', [
            'slug_recu' => $slug,
        ]);
    }
    
    // 3. Route avec Contraintes (Regex)
    #[Route('/admin/post/{id}', name: 'admin_post_edit', methods: ['GET', 'POST'], requirements: ['id' => '\d+'])]
    public function edit(int $id): Response
    {
        // (Ne matchera que si 'id' est un nombre (\d+))
        // ...
    }
}
3.1 Concept 5 : Le Contrôleur (La Logique)

Le Contrôleur (une classe PHP) est la "colle" (la logique) de la requête.
Rôle : Recevoir la Request (et les services injectés), faire appel au "Modèle" (ex: Doctrine), et retourner une Response.

On hérite de AbstractController pour avoir accès aux raccourcis (render(), json()...).

Exemple (src/Controller/ApiUserController.php)
namespace App\Controller;

use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; // (L'objet Requête)
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; // (PHP 8+)

class ApiUserController extends AbstractController
{
    // (Injection de dépendance (DI))
    public function __construct(
        private UserRepository $userRepository
    ) {}

    #[Route('/api/users')]
    public function getUsers(Request $request): JsonResponse
    {
        // 1. Lire la requête (ex: paramètre ?limit=10)
        $limit = $request->query->get('limit', 10);

        // 2. Appeler le "Modèle" (Doctrine)
        $users = $this->userRepository->findBy([], [], $limit);

        // 3. Retourner une Réponse (JSON)
        // (Le raccourci 'json()' gère la sérialisation)
        return $this->json([
            'users' => $users,
        ]);
    }
    
    #[Route('/page/contact')]
    public function contactPage(): Response
    {
        // 3b. Retourner une Réponse (HTML/Twig)
        return $this->render('pages/contact.html.twig', [
            'form_status' => 'pending',
        ]);
    }
}
3.2 Concept 6 : Twig (Vues)

Twig est le moteur de template (moteur de vues) de Symfony. Il sépare la logique (PHP) de l'affichage (HTML).

Syntaxe :
{% templatetag openvariable %} ... {% templatetag closevariable %} : Affiche une variable (ex: {% templatetag openvariable %} user.nom {% templatetag closevariable %}).
{% templatetag openblock %} ... {% templatetag endblock %} : Exécute une logique (ex: {% templatetag openblock %} if ... {% templatetag endblock %}, {% templatetag openblock %} for ... {% templatetag endblock %}).
{# ... #} : Commentaire.

Exemple (templates/blog/show.html.twig)
{# 1. Héritage du layout principal #}
{% extends 'base.html.twig' %}

{# 2. Remplir le "bloc" 'title' (défini dans base.html.twig) #}
{% block title %}Post: {{ post.titre }}{% endblock %}

{# 3. Remplir le "bloc" 'body' #}
{% block body %}
    

{{ post.titre | upper }}

Par {{ post.auteur.nom }}

{{ post.contenu | raw }} {# | raw = Ne pas échapper le HTML #}

{# 4. Logique (Boucle) #}

Commentaires ({{ post.commentaires | length }})

    {% for commentaire in post.commentaires %}
  • {{ commentaire.texte }}
  • {% else %}
  • Aucun commentaire.
  • {% endfor %}
{# 5. Logique (Condition) #} {% if is_admin %} Modifier {% endif %} {# 6. Inclure un autre template #} {% include 'partials/_footer.html.twig' %} {% endblock %}
3.3 Concept 7 : Doctrine (ORM / Modèle)

Doctrine est l'ORM (Object-Relational Mapper) par défaut de Symfony. C'est la couche "Modèle" (la base de données).

Il "mappe" (relie) une table SQL (ex: users) à une classe PHP (User).

1. L'Entité (Entity)

Une classe PHP (POPO) dans src/Entity/ qui représente une table. On utilise les Attributs (#[...]) pour définir le mapping.

// (src/Entity/User.php)
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\UserRepository;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 100, unique: true)]
    private ?string $email = null;
    
    #[ORM\Column(length: 255)]
    private ?string $nom = null;

    // ... (Getters & Setters)
}

Commande (MakerBundle) : php bin/console make:entity User

2. Le Repository (Lire les données)

Classe (dans src/Repository/) utilisée pour **lire** (SELECT) les données. On l'injecte (DI) dans le contrôleur.

// (Controller)
use App\Repository\UserRepository;

public function show(UserRepository $userRepository, int $id): Response
{
    // (Méthodes magiques)
    $user = $userRepository->find($id);
    $user_email = $userRepository->findOneBy(['email' => 'test@test.com']);
    $admins = $userRepository->findBy(['role' => 'admin'], ['nom' => 'ASC']);
    
    // (Méthode custom (DQL))
    $users_actifs = $userRepository->findActifs();
    
    // ...
}
3. L'EntityManager (Écrire les données)

L'EntityManager ($em) gère l'écriture (INSERT, UPDATE, DELETE).

use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;

// (Controller)
#[Route('/user/create')]
public function create(EntityManagerInterface $em): Response
{
    // 1. Créer l'objet PHP
    $user = new User();
    $user->setNom("Alice");
    $user->setEmail("alice@mail.com");

    // 2. "Persist" (Dire à Doctrine de "gérer" cet objet)
    $em->persist($user);
    
    // 3. "Flush" (Exécuter le SQL (INSERT) dans la DB)
    $em->flush();
    
    return $this->json(['id' => $user->getId()]);
}
3.4 Concept 8 : Formulaires (Symfony Forms)

Le composant "Form" gère le cycle de vie complet d'un formulaire : création (HTML), "data binding" (liaison Request -> Objet), et validation.

1. Le FormType (Classe)

(php bin/console make:form UserType)

// (src/Form/UserType.php)
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email', EmailType::class)
            ->add('nom', TextType::class)
            // (Si le Form est lié à l'Entité User,
            // les types sont auto-détectés !)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        // (Lie ce formulaire à l'Entité User)
        $resolver->setDefaults(['data_class' => User::class]);
    }
}
2. Le Contrôleur (Utilisation)
// (Controller)
#[Route('/user/new')]
public function new(Request $request, EntityManagerInterface $em): Response
{
    $user = new User();
    
    // 1. Créer le formulaire
    $form = $this->createForm(UserType::class, $user);

    // 2. Gérer la requête (POST)
    $form->handleRequest($request);
    
    if ($form->isSubmitted() && $form->isValid()) {
        // (OK: $user a été hydraté)
        $em->persist($user);
        $em->flush();
        
        return $this->redirectToRoute('homepage');
    }

    // 3. Afficher (GET)
    return $this->render('user/new.html.twig', [
        'userForm' => $form->createView()
    ]);
}
3. La Vue (new.html.twig)
{{ form_start(userForm) }}

  {{ form_row(userForm.email) }}
  {{ form_row(userForm.nom) }}
  
  
  
{{ form_end(userForm) }}
4.1 Concept 9 : Sécurité (SecurityBundle)

Le SecurityBundle est le composant (très puissant, très complexe) qui gère l'Authentification (AuthN - "Qui es-tu ?") et l'Autorisation (AuthZ - "Qu'as-tu le droit de faire ?").

Tout est configuré dans config/packages/security.yaml.

Diagramme (Flux security.yaml)
(Requête: GET /admin)
      |
      ▼
+---------------------+
| Firewall (le "Mur") | (défini dans 'security.yaml')
| (match: ^/admin)    |
+---------------------+
      | (STOP: Auth requise)
      ▼
+---------------------+
| Authenticator       | (Ex: Formulaire de login)
| (Vérifie User/Pass) |
+---------------------+
      | (OK: User "Bob" (ROLE_ADMIN))
      ▼
+---------------------+
| Access Control      | (Règle: "path: ^/admin, roles: ROLE_ADMIN")
| (Autorisation)      |
+---------------------+
      | (Accès OK)
      ▼
(Controller: AdminController)
4.2 Addon : API Platform

API Platform (un Bundle/Framework séparé, mais 100% Symfony) est un "wrapper" (enveloppe) "magique" qui lit vos Entités Doctrine (3.3) et génère **automatiquement** une API REST (ou GraphQL) complète (CRUD, filtres, pagination, documentation OpenAPI/Swagger).

Exemple (Magique)

Vous écrivez (presque) *juste* ça :

// (src/Entity/User.php)
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource; // (Importer)
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource] // (Dire à API Platform d'exposer cette Entité)
class User
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    #[ORM\Column]
    public ?string $nom = null;
    
    // ...
}

Résultat : API Platform crée *automatiquement* les routes, les contrôleurs, et la documentation pour :

  • GET /api/users (Liste paginée)
  • POST /api/users (Créer)
  • GET /api/users/{id} (Lire)
  • PUT /api/users/{id} (Remplacer)
  • DELETE /api/users/{id} (Supprimer)
4.3 Addons : Messenger & Mercure
Messenger (Asynchrone / Queues)

Le composant "Messenger" gère les **Queues** (files d'attente, ex: RabbitMQ, SQS).

Cas d'usage : Un utilisateur s'inscrit (Requête HTTP). Le Contrôleur (rapide) "dispatch" (envoie) un EmailBienvenueMessage dans la queue, et retourne "OK" (200) à l'utilisateur.

Un "Handler" (worker) (processus séparé, lent) consomme le message et envoie *vraiment* l'email (sans bloquer l'utilisateur).

Mercure (Push Temps Réel)

Mercure (un protocole + un Hub) permet au **serveur** (PHP) de "pousser" (push) des données aux **clients** (JS) en temps réel (Server-Sent Events).

Cas d'usage : Une notification "live", un Tchat.

4.4 Cas d'Usage (Vitrine)

Symfony (Framework ou Composants) est utilisé par des milliers d'applications "Entreprise" et Open Source.

ProjetUsage
Applications "Entreprise" (SaaS)Le cas d'usage N°1. (Back-offices, CRM, ERP, SaaS B2B). (Robuste, long terme).
API (Backends)Utilisé comme "micro-framework" ou avec API Platform pour servir des backends (API REST/GraphQL) pour des Frontends (React/Vue).
Drupal(CMS) Drupal (depuis la v8) est entièrement reconstruit sur les Composants Symfony.
Prestashop(E-commerce) Prestashop (depuis la v1.7) utilise les Composants Symfony.
Laravel(Framework PHP) Le concurrent N°1 de Symfony utilise... de nombreux Composants Symfony (ex: Console, HttpClient).
5.1 Cheat-sheet (CLI)
symfony (Le "Helper")
# 1. Créer un projet (Full-stack)
symfony new mon-projet --webapp

# 2. Lancer le serveur local
symfony server:start

# 3. Voir la config (ex: Secrets)
symfony var:export --reveal
composer (Les Paquets)
# 1. Installer un Bundle/Composant
# (Symfony Flex le configure auto)
composer require twig
composer require doctrine
composer require api

# 2. Installer (Dev)
composer require maker --dev
php bin/console (Le Cœur Applicatif)
# 1. Lister toutes les commandes
php bin/console list

# 2. Débugger (Super-utile)
php bin/console debug:router
php bin/console debug:autowiring

# 3. Maker (Générer du code)
php bin/console make:controller BlogController
php bin/console make:entity User
php bin/console make:form UserType
php bin/console make:auth

# 4. Doctrine (DB)
php bin/console doctrine:database:create
php bin/console make:migration
php bin/console doctrine:migrations:migrate