Tutoriels Symfony + Twig 02 May 2026 12 min de lecture

Jour 8 - Gérer les images du blog sans casser la prod

On met en place un upload d’images fiable pour les articles: validation, stockage et fallback quand le fichier manque.

Jour 8 - Gérer les images du blog sans casser la prod - article technique

Les images cassées détruisent la crédibilité d’un blog. Le sujet n’est pas “juste upload un fichier”, c’est garantir un flux fiable.

On va sécuriser l’upload et afficher un fallback quand l’image n’existe pas.

Objectif d’apprentissage

Permettre à l’éditeur de gérer les images d’articles sans erreur de chemin, sans type de fichier dangereux et sans casser le front.

Ce que tu vas pratiquer aujourd’hui

  • Valider les types de fichiers et le poids.
  • Stocker proprement dans public/uploads/blog.
  • Générer des noms stables et uniques.
  • Afficher une image de secours en front.

1. Ajouter le champ image dans le FormType

Le champ upload ne doit pas mapper directement un chemin brut sans contrôle.

On valide MIME et taille avant de déplacer le fichier.

$builder->add('featuredImageFile', FileType::class, [
    'mapped' => false,
    'required' => false,
    'constraints' => [
        new File(
            maxSize: '4M',
            mimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
        ),
    ],
]);

2. Déplacer le fichier avec un nom propre

On crée un nom unique pour éviter l’écrasement de fichiers et les collisions.

Conserve une extension contrôlée.

if ($file instanceof UploadedFile) {
    $filename = sprintf(
        '%s-%s.%s',
        $slugger->slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME))->lower(),
        time(),
        $file->guessExtension() ?: 'jpg'
    );

    $file->move($this->getParameter('blog_upload_dir'), $filename);
    $post->setFeaturedImagePath($filename);
}

3. Prévoir un fallback en Twig

Même avec un bon upload, un fichier peut disparaître après un mauvais déploiement ou une erreur serveur.

Le fallback protège l’expérience utilisateur.

{% set imageUrl = post.featuredImagePath
    ? asset('uploads/blog/' ~ post.featuredImagePath)
    : asset('uploads/blog/default-cover.png') %}

<img src="{{ imageUrl }}" alt="{{ post.title }}" loading="lazy">

Checklist de fin de session

  • Upload image contrôlé.
  • Nommage de fichier stable.
  • Fallback visuel en place.
  • Aucune erreur front si image manquante.

Erreurs fréquentes à éviter

  • Sauter la vérification finale parce que “ça marche chez moi”.
  • Mélanger trop de logique dans le controller au lieu de garder un flux clair.
  • Oublier la cohérence entre la donnée, le template Twig et le comportement en production.

Pourquoi cette étape compte en conditions réelles

Dans un vrai projet client, chaque étape technique doit rester compréhensible par l’équipe, duplicable sur un autre environnement et fiable dans le temps. Ici, l’objectif est de transformer la théorie en un flux de travail concret, avec des décisions simples que tu peux défendre en revue de code.

Si tu appliques sérieusement les points du jour (valider les types de fichiers et le poids.), tu réduis la dette technique dès le départ et tu facilites la suite: SEO, publication, maintenance et déploiement. C’est exactement la différence entre un blog “démo” et un blog exploitable en production.

Mini plan de révision

  • Reprends ce point et explique-le à voix haute comme si tu faisais un code review : Valider les types de fichiers et le poids.
  • Reprends ce point et explique-le à voix haute comme si tu faisais un code review : Stocker proprement dans public/uploads/blog.
  • Reprends ce point et explique-le à voix haute comme si tu faisais un code review : Générer des noms stables et uniques.

Exercice rapide

Ajoute une commande pour lister les images référencées en BDD mais absentes du disque.

Et demain ?

Demain, on ajoute recherche, filtres et pagination pour rendre le blog utilisable avec plus de contenu.

Partager

Faire circuler cet article

Si ce contenu peut aider quelqu’un dans son projet, tu peux le partager directement.

LinkedIn X WhatsApp

Tu dois structurer un backend, clarifier une API ou reprendre un existant en production ?

Échanger sur ton besoin