Tutoriel MVC · Chapitre 06

Créer les vues
et les partials.

Transformez les données du contrôleur en pages sûres, accessibles et faciles à maintenir.

DATAVIEWHTMLUSER

Les données existent. Il faut maintenant les rendre compréhensibles.

Les routes savent reconnaître les demandes et les contrôleurs savent préparer les réponses. Mais un tableau PHP contenant des tâches ne constitue pas encore une expérience utilisateur. Il faut organiser les informations, créer une hiérarchie visuelle, proposer les bonnes actions et expliquer clairement les erreurs.

C’est le rôle de la couche View. Elle se trouve à la frontière entre les données internes et ce que la personne voit réellement. Une bonne vue ne se contente pas de produire du HTML valide : elle protège les sorties, prévoit les collections vides, conserve les saisies incorrectes et rend le parcours évident sur ordinateur comme sur téléphone.

Le résultat attendu

À la fin du chapitre, l’application possédera une liste de tâches, une fiche détaillée, des formulaires create et edit, un layout commun, des partials réutilisables, des erreurs accessibles et des confirmations après redirection.

06.1

Comprendre le rôle d’une vue

Une vue transforme les données préparées par le contrôleur en document destiné à l’utilisateur. Dans une application Web classique, ce document est généralement du HTML accompagné de liens, formulaires et messages.

La vue ne décide pas quelles tâches appartiennent à l’utilisateur et ne lance pas la création d’une ressource. Ces décisions ont déjà été prises avant le rendu. Elle reçoit un contrat de données et se concentre sur leur présentation.

Cette séparation permet de modifier le design sans réécrire les règles métier et de tester le contrôleur sans analyser toute la mise en page.

À retenir

La vue présente une décision déjà prise; elle ne remplace ni le contrôleur ni le modèle.

06.2

Transmettre les données explicitement

Le second argument de view() constitue le contrat entre le contrôleur et le template. Chaque clé devient une variable disponible au rendu : tasks, title, currentFilter ou permissions.

Choisissez des noms qui décrivent le contenu, pas son apparence. tasks restera pertinent si la liste devient une grille; leftColumnTasks enfermerait la vue dans un design particulier.

Évitez les variables magiques disponibles partout sans déclaration. Un contrat explicite permet de savoir ce dont une vue dépend et produit une erreur compréhensible lorsqu’une donnée manque.

À retenir

Une vue doit annoncer ses dépendances par les données que le contrôleur lui transmet.

phpaml — zsh
return view('tasks/index', [
    'title' => 'My tasks',
    'tasks' => $tasks,
    'canCreate' => $request->user()->can('create', Task::class),
]);
06.3

Échapper toutes les sorties

Une valeur venant d’un utilisateur peut contenir du HTML ou du JavaScript. L’afficher directement permettrait à ce contenu de devenir une partie active de la page : c’est une vulnérabilité XSS.

Échappez le titre, la description, le nom et toute autre valeur dynamique selon le contexte HTML. L’échappement d’un texte, d’un attribut, d’une URL et d’un script ne suit pas exactement les mêmes règles.

N’utilisez une sortie HTML brute que pour un contenu explicitement approuvé et nettoyé. Le simple fait qu’une valeur provienne de la base ne la rend pas sûre : elle a pu être dangereuse avant son enregistrement.

À retenir

Validez à l’entrée pour le métier; échappez à la sortie pour le contexte d’affichage.

phpaml — zsh
<h2><?= e($task->title) ?></h2>
<p><?= e($task->description) ?></p>
06.4

Afficher conditions et collections

Une liste de tâches doit gérer au moins trois états : chargement réussi avec résultats, collection vide et parfois erreur de récupération. Une vue robuste rend chacun de ces états intentionnellement.

Dans la boucle, donnez à chaque élément une structure cohérente et limitez les décisions au rendu : afficher le badge terminé, la date ou le bouton permis. Une règle comme déterminer si la tâche est en retard doit idéalement être préparée par le modèle.

L’état vide n’est pas une erreur technique. Il guide l’utilisateur vers sa première action avec un texte utile et un lien vers le formulaire de création.

À retenir

Chaque état possible des données doit posséder une présentation volontaire.

phpaml — zsh
<?php if (empty($tasks)): ?>
  <section class="empty-state">
    <h2>No tasks yet</h2>
    <a href="<?= route('tasks.create') ?>">Create your first task</a>
  </section>
<?php else: ?>
  <?php foreach ($tasks as $task): ?>
    <?php view('tasks/_card', ['task' => $task]); ?>
  <?php endforeach; ?>
<?php endif; ?>
06.5

Extraire des partials réutilisables

Un partial est un fragment de présentation réutilisé dans plusieurs pages : header, navigation, footer, message flash ou carte de tâche. Il évite la duplication tout en conservant du HTML simple.

Extrayez un fragment lorsqu’il représente une unité reconnaissable ou lorsqu’une modification devrait s’appliquer partout. Ne découpez pas chaque balise dans son propre fichier : une fragmentation excessive rend la page plus difficile à suivre.

Transmettez au partial les données dont il a besoin. Une carte Task reçoit une tâche et les permissions pertinentes; elle ne devrait pas chercher silencieusement l’utilisateur ou interroger la base.

À retenir

Un bon partial possède une responsabilité visuelle claire et un petit contrat de données.

06.6

Construire un layout commun

Le layout contient le squelette stable du document : doctype, langue, métadonnées, feuilles de style, header, zone principale et footer. Les pages fournissent ensuite leur contenu spécifique.

Centraliser ce squelette garantit que toutes les pages reçoivent les mêmes fondations d’accessibilité et de sécurité. Le titre et la description peuvent toutefois varier selon la route.

Placez les ressources communes une seule fois et gardez une zone explicite pour le contenu. Un layout ne doit pas cacher des appels métier ou imposer des données que certaines pages ne possèdent pas.

À retenir

Le layout centralise la structure commune sans effacer l’identité de chaque page.

06.7

Créer les formulaires

Le formulaire create envoie une nouvelle tâche vers store. Le formulaire edit envoie les modifications vers update. Leur action et leur méthode doivent correspondre exactement aux routes définies au chapitre 4.

Chaque champ possède un label lié, une valeur précédente, une indication utile et une zone d’erreur. Le bouton décrit l’action : Créer la tâche ou Enregistrer les modifications, plutôt qu’un vague Envoyer.

Incluez le jeton CSRF dans toute mutation Web. Pour PATCH et DELETE, utilisez le mécanisme de substitution de méthode du framework lorsque le navigateur ne peut envoyer directement que GET et POST.

À retenir

Un formulaire est une interface vers un contrat HTTP, pas seulement un groupe de champs.

phpaml — zsh
<form method="POST" action="<?= route('tasks.store') ?>">
  <?= csrf_field() ?>
  <label for="title">Task title</label>
  <input id="title" name="title"
         value="<?= e(old('title')) ?>"
         aria-describedby="title-error">
  <?php if ($errors->has('title')): ?>
    <p id="title-error" role="alert">
      <?= e($errors->first('title')) ?>
    </p>
  <?php endif; ?>
  <button type="submit">Create task</button>
</form>
06.8

Afficher les erreurs de validation

Lorsqu’une saisie est invalide, l’utilisateur doit comprendre ce qui s’est passé, où corriger et comment réussir. Une bordure rouge sans texte n’est pas une explication suffisante.

Affichez un résumé en haut lorsque plusieurs erreurs existent, puis le message précis près de chaque champ. Associez le message au contrôle avec les attributs accessibles appropriés.

Réaffichez l’ancienne saisie pour éviter de forcer l’utilisateur à tout recommencer, sauf pour les données sensibles comme les mots de passe. Conservez un langage humain plutôt que les noms internes de colonnes.

À retenir

Une erreur utile explique le problème et rapproche l’utilisateur de la solution.

06.9

Utiliser les messages flash

Après une redirection, le nouveau document ne possède plus naturellement le résultat de la requête précédente. Un message flash transporte cette information pendant une seule requête.

Utilisez-le pour confirmer une création, modification ou suppression, et parfois pour annoncer un avertissement. Le message doit être bref, spécifique et visible sans bloquer la navigation.

Le partial flash peut choisir un style selon success, warning ou error. Il doit aussi rester compréhensible sans dépendre uniquement d’une couleur et être annoncé correctement aux technologies d’assistance.

À retenir

Le flash confirme une transition; il ne remplace pas le contenu durable de la page.

06.10

Tester le rendu et l’accessibilité

Un test de vue vérifie que les données importantes apparaissent, que les valeurs dangereuses sont échappées et que les états vide et erreur sont présents. Il ne doit pas dépendre de chaque classe CSS.

Testez les liens et actions de formulaires afin qu’ils suivent les routes nommées. Vérifiez également labels, hiérarchie des titres, langue du document, texte alternatif et navigation au clavier.

Complétez les tests automatisés par une lecture réelle sur mobile et tablette. Une page techniquement valide peut rester inutilisable si le formulaire déborde ou si le message d’erreur est invisible.

À retenir

Testez ce que l’utilisateur peut lire, comprendre et accomplir.

Atelier guidé

Construisez toutes les vues de Task.

  1. Créez le layout avec métadonnées, header, main et footer.
  2. Construisez index avec liste et état vide.
  3. Extrayez une carte de tâche réutilisable.
  4. Créez show, create et edit.
  5. Ajoutez CSRF, anciennes valeurs et erreurs accessibles.
  6. Affichez les messages flash après redirection.
  7. Testez une charge XSS, l’état vide et les liens nommés.

Correction raisonnée

Relisez la page comme un utilisateur et comme un attaquant.

L’utilisateur doit comprendre la hiérarchie, trouver l’action suivante et corriger une erreur sans perdre sa saisie. L’attaquant, lui, ne doit jamais transformer un titre de tâche en code actif. Vérifiez ces deux perspectives avant de considérer la vue terminée.

Faut-il créer un partial pour chaque élément ?

Non. Extrayez les unités réutilisées ou conceptuellement autonomes. Gardez ensemble le HTML qui se comprend mieux ensemble.

En résumé

Une vue réussie rend les données sûres, lisibles et actionnables.

Vous savez maintenant construire une page sans mélanger présentation et métier. Le contrôleur fournit un contrat explicite; la vue échappe les valeurs, compose le layout et les partials, puis adapte le rendu aux différents états de données.

  • transmettez uniquement les données nécessaires
  • échappez chaque sortie selon son contexte
  • prévoyez résultat, vide et erreur
  • utilisez partials et layout sans fragmenter excessivement
  • rendez formulaires et erreurs accessibles
  • testez le comportement visible, pas le détail CSS

Au chapitre 7, nous donnerons à ces pages leur identité visuelle avec CSS, JavaScript progressif, images et une stratégie propre pour les ressources publiques et le cache navigateur.

Chapitre 05Chapitre 07 · À venir 🔒