
Etape 4 : Vues Blade pour l'affichage et le formulaire d'ajout
Apprenez à concevoir des vues Blade dans Laravel pour présenter la liste des notes, afficher une note détaillée et construire un formulaire d'ajout interactif.
Introduction aux vues Blade : la puissance du moteur de template de Laravel
Jusqu'à présent, nos contrôleurs retournent de simples chaînes de caractères. Pour une application web réelle, nous avons besoin de présenter les informations de manière structurée et conviviale, généralement en HTML. C'est là qu'interviennent les vues Blade. Blade est le moteur de template simple mais puissant fourni avec Laravel. Contrairement à d'autres moteurs de template PHP populaires, Blade ne vous empêche pas d'utiliser du code PHP brut dans vos vues. En fait, toutes les vues Blade sont compilées en code PHP pur et mises en cache jusqu'à ce qu'elles soient modifiées, ce qui signifie que Blade n'ajoute pratiquement aucune surcharge à votre application.
Les fichiers de vues Blade utilisent l'extension .blade.php et sont généralement stockés dans le répertoire resources/views. Blade fournit une syntaxe pratique pour des tâches courantes telles que l'affichage de données, les structures de contrôle (conditions, boucles), l'héritage de templates (layouts), et l'inclusion de sous-vues. Cela rend la création d'interfaces utilisateur dynamiques et maintenables beaucoup plus aisée.
Pour notre mini-gestionnaire de notes, nous allons créer plusieurs vues Blade : une pour lister toutes les notes (index.blade.php), une pour afficher une note spécifique (show.blade.php), et une pour présenter le formulaire de création d'une nouvelle note (create.blade.php). Nous allons également explorer la création d'un layout de base pour éviter la duplication de code HTML commun.
Création d'un layout de base avec Blade
Avant de créer les vues spécifiques à nos notes, il est judicieux de mettre en place un layout de base. Un layout contient la structure HTML commune à plusieurs pages de votre site (comme le , la navigation, le pied de page). Les vues spécifiques viendront ensuite étendre ce layout et y injecter leur contenu unique.
Créez un nouveau répertoire layouts à l'intérieur de resources/views. Ensuite, dans resources/views/layouts, créez un fichier nommé app.blade.php avec le contenu suivant :
{{ config('app.name', 'Laravel') }} - @yield('title')
Mon Gestionnaire de Notes
@yield('content')
Les directives Blade importantes ici sont :
{{ ... }}: Utilisé pour afficher des données. Blade échappe automatiquement les données pour prévenir les attaques XSS.@yield('sectionName'): Définit un emplacement où le contenu d'une section définie dans une vue enfant sera injecté. Nous avons@yield('title')pour le titre de la page et@yield('content')pour le contenu principal.route('notes.index'): Génère l'URL pour la route nommée 'notes.index'.
Ce layout simple utilise Bootstrap 5 (via un CDN) pour un style de base. Vous pouvez bien sûr utiliser n'importe quel framework CSS ou vos propres styles.
Vue pour lister les notes (`index.blade.php`)
Maintenant, créons la vue pour afficher la liste des notes. Créez un répertoire notes à l'intérieur de resources/views. Dans resources/views/notes, créez un fichier index.blade.php :
@extends('layouts.app')
@section('title', 'Liste des Notes')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-3">
<h2>Toutes mes notes</h2>
<a href="{{ route('notes.create') }}" class="btn btn-primary">Ajouter une note</a>
</div>
@if(session('success'))
<div class="alert alert-success"
{{ session('success') }}
</div>
@endif
@if($notes->isEmpty())
<p>Aucune note pour le moment. <a href="{{ route('notes.create') }}">Créez votre première note !</a></p>
@else
<ul class="list-group">
@foreach ($notes as $note)
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{{ route('notes.show', $note->id) }}" class="text-decoration-none">
{{ $note->title }}
</a>
<small class="text-muted">Créée le {{ $note->created_at->format('d/m/Y') }}</small>
</li>
@endforeach
</ul>
@endif
@endsectionExplications :
@extends('layouts.app'): Indique que cette vue étend le layoutapp.blade.php.@section('title', 'Liste des Notes'): Définit le contenu de la section 'title' du layout.@section('content') ... @endsection: Définit le contenu principal de la page.@if($notes->isEmpty()) ... @else ... @endif: Structure conditionnelle pour afficher un message si aucune note n'existe.@foreach ($notes as $note) ... @endforeach: Boucle pour itérer sur la collection de$notes(que le contrôleur devra passer à cette vue).{{ $note->title }}: Affiche le titre de la note.{{ route('notes.show', $note->id) }}: Génère l'URL pour afficher une note spécifique, en passant son ID.{{ $note->created_at->format('d/m/Y') }}: Affiche la date de création formatée.created_atest automatiquement un objet Carbon par Eloquent.
Modifions la méthode index de NoteController pour passer les notes à cette vue :
// Dans app/Http/Controllers/NoteController.php
use App\Models\Note;
public function index()
{
$notes = Note::orderBy('created_at', 'desc')->get(); // Récupère toutes les notes, les plus récentes en premier
return view('notes.index', ['notes' => $notes]);
// Ou de manière équivalente avec la fonction compact() :
// return view('notes.index', compact('notes'));
}La fonction view('notes.index', ...) charge la vue resources/views/notes/index.blade.php et lui passe un tableau de données. La clé 'notes' dans ce tableau devient la variable $notes disponible dans la vue Blade.
Vue pour afficher une note spécifique (`show.blade.php`)
Créez resources/views/notes/show.blade.php pour afficher les détails d'une seule note :
@extends('layouts.app')
@section('title', $note->title)
@section('content')
<div class="card">
<div class="card-header">
<h2>{{ $note->title }}</h2>
</div>
<div class="card-body">
<p class="card-text">{!! nl2br(e($note->content)) !!}</p>
<!-- nl2br pour convertir les sauts de ligne en <br> -->
<!-- e() pour échapper le contenu -->
<!-- {!! !!} pour ne pas échapper le HTML de <br> -->
</div>
<div class="card-footer text-muted">
Créée le: {{ $note->created_at->format('d/m/Y H:i') }} | Dernière modification: {{ $note->updated_at->format('d/m/Y H:i') }}
</div>
</div>
<div class="mt-3">
<a href="{{ route('notes.index') }}" class="btn btn-secondary">Retour à la liste</a>
<!-- Plus tard, on ajoutera des liens pour éditer et supprimer -->
</div>
@endsectionNotez l'utilisation de {!! nl2br(e($note->content)) !!}. D'abord, e($note->content) échappe le contenu pour la sécurité (prévention XSS). Ensuite, nl2br() convertit les nouvelles lignes (\n) en balises HTML . Enfin, {!! ... !!} est utilisé pour afficher le résultat sans ré-échapper les balises , permettant ainsi de conserver les sauts de ligne saisis par l'utilisateur.
Modifions la méthode show de NoteController :
// Dans app/Http/Controllers/NoteController.php
public function show(string $noteId) // Correspond au {note} de la route, mais c'est l'ID
{
$note = Note::findOrFail($noteId); // Trouve la note ou lève une exception 404 si non trouvée
return view('notes.show', compact('note'));
}Nous utilisons findOrFail($noteId) qui est très pratique : si la note avec l'ID donné n'est pas trouvée, Laravel affichera automatiquement une page d'erreur 404.
Vue pour le formulaire d'ajout (`create.blade.php`)
Créez resources/views/notes/create.blade.php pour le formulaire de création :
@extends('layouts.app')
@section('title', 'Ajouter une nouvelle note')
@section('content')
<h2>Créer une nouvelle note</h2>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('notes.store') }}" method="POST">
@csrf
<!-- Protection CSRF : indispensable pour les formulaires POST -->
<div class="mb-3">
<label for="title" class="form-label">Titre</label>
<input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" value="{{ old('title') }}" required>
@error('title')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="content" class="form-label">Contenu</label>
<textarea class="form-control @error('content') is-invalid @enderror" id="content" name="content" rows="5" required>{{ old('content') }}</textarea>
@error('content')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Enregistrer la note</button>
<a href="{{ route('notes.index') }}" class="btn btn-secondary">Annuler</a>
</form>
@endsectionPoints importants ici :
@csrf: Directive Blade essentielle qui génère un champ de token CSRF caché. Laravel vérifie ce token pour protéger contre les attaques de type Cross-Site Request Forgery. Tous vos formulaires POST, PUT, PATCH, DELETE doivent l'inclure.action="{{ route('notes.store') }}" method="POST": Le formulaire soumettra ses données à la route nomméenotes.storevia la méthode POST.value="{{ old('title') }}"et{{ old('content') }}: La fonction helperold()permet de récupérer la valeur précédemment soumise pour un champ, ce qui est utile si la validation échoue et que vous devez réafficher le formulaire avec les données de l'utilisateur et les messages d'erreur.@error('fieldName') ... @enderror: Affiche un message d'erreur spécifique si la validation pour ce champ a échoué. La variable$messagecontient le message d'erreur. La classeis-invalidde Bootstrap est ajoutée dynamiquement.$errors->any()et$errors->all(): Permettent d'afficher une liste de toutes les erreurs de validation en haut du formulaire.
Modifions la méthode create de NoteController pour afficher ce formulaire :
// Dans app/Http/Controllers/NoteController.php
public function create()
{
return view('notes.create');
}La méthode store, qui gérera la soumission de ce formulaire, sera détaillée dans le prochain chapitre sur la gestion de la soumission et la persistance des données.
Avec ces vues en place, notre application commence à prendre forme visuellement. L'utilisateur peut maintenant naviguer entre la liste des notes, voir une note détaillée et accéder au formulaire pour en créer une nouvelle. La prochaine étape cruciale sera de rendre ce formulaire fonctionnel en implémentant la logique de sauvegarde et de validation dans la méthode store de notre contrôleur.