Les bases 3/6 : Création des vues

Tutoriels
Publié par William

Découverte des notions fondamentales de Laravel à travers un cas concret.

Sommaire

  1. Création du modèle
  2. Création du contrôleur
  3. Création des vues
  4. Validation des données
  5. Contrôle d’accès
  6. Tests

Le concept

Laravel dispose de son propre moteur de template nommé Blade. Celui-ci permet d’injecter facilement de la dynamique au sein du html.

Voici un exemple d’une variable injecté avec du php pur :

Bonjour, je m'appelle <?= $name ?>

Et le même résultat avec Blade :

Bonjour, je m'appelle {{ $name }}

Pour être plus exact avec l'exemple en PHP pur, il aurait fallu englober l’utilisation de la variable par l’appel de la fonction htmlspecialchars , détail non-négligeable car il permet de se prémunir contre les attaques XSS. C'est aussi ça l'avantage d'utiliser un moteur de template.

Blade offre aussi de nombreuses fonctions appelées directives : des conditions, des boucles, etc.

Mais ce moteur permet surtout de fragmenter ses vues afin de limiter la duplication du code et ainsi permettre de changer un design de manière plus optimisée.

Cette fragmentation est gérable de 2 manières. Historiquement via l’héritage des vues et aussi via la notion de composants introduite à la version 7.

Nous allons dans ce tutoriel utiliser les composants pour la gestion de nos vues. C’est parti !

Avant de continuer assurez-vous d’avoir compris comment, depuis le contrôleur, des variables sont injectées à la vue.

Création du layout

Tout d’abord nous allons commencer par le layout. Le layout définit la structure globale de nos vues. Il contient à peu près tout sauf le contenu spécifique d’une page.

Voici notre fichier resources/views/components/layout.blade.php :

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="utf8">
        <title>{{ $title ?? 'Laravel France : Les bases' }}</title>
    </head>
    <body>
        <header><h1><a href="/">Laravel France: Les bases</a></h1></header>
        <main>{{ $slot }}</main>
    </body>
</html>

Le point d’attention est la présence de deux variables qui sont toutes deux des slots c’est à dire qu’elles seront remplacées par du contenu définit dans les vues, c'est ce qu’on va voir dans le paragraphe suivant.

A cet instant, gardons en tête que la variable $title sera remplacée par 'Laravel France : Les bases' si elle n’est pas définit au sein d’une vue et que la variable $slot permet d’injecter le contenu d’une vue.

Afin de simplifier la compréhension des vues au maximum, j’ai volontairement exclu toutes notions de style.

Création des vues de lecture

Maintenant que l’ossature de nos pages est définit, nous allons définir le contenu de deux d’entre elles :

  • La page index qui liste nos restaurants
  • La page show qui affiche les informations d’un restaurant

Voici le contenu de la page index définit dans le fichier resources/views/restaurants/index.blade.php :

<x-layout>
    <x-slot:title>Liste des restaurants</x-slot:title>

    <h2>Liste des restaurants</h2>
    <div style="margin-bottom: 1rem">
        <a href="{{ route('restaurants.create') }}">Créer un restaurant</a>
    </div>
    <table>
        <thead>
            <tr>
                <th>Nom</th>
                <th>Type</th>
                <th>Restaurateur</th>
            </tr>
        </thead>
        <tbody>
            @foreach($restaurants as $restaurant)
                <tr>
                    <td>
                        <a href="{{ route('restaurants.show', $restaurant) }}">{{ $restaurant->name }}</a>
                    </td>
                    <td>{{ $restaurant->type }}</td>
                    <td>{{ $restaurant->user->name }}</td>
                </tr>
            @endforeach
        </tbody>
    </table>
</x-layout>

On distingue plusieurs choses. La première c'est la présence de balises un peu bizarre préfixées par x-. Ces balises permettent à Blade de les interpréter comme des composants.

On a donc un appel au composant x-layout qui est celui qu’on a précédemment écrit. Tout le contenu compris entre ses balises sara injecté à la place de la variable $slot dans le layout.

Tout sauf le contenu de la balise x-slot:title qui elle permet d’injecter son contenu à la place de la variable $title définit dans le layout.

Autre point notable est l’utilisation pour la première d’une directive blade: @foreach qui permet de boucler sur les éléments du tableau $restaurants qui a été injecté dans la vue via le contrôleur.

Enfin, l’utilisation de la fonction route() qui permet de résoudre, depuis son nom, le chemin d’une route définit dans le fichier routes/web.php.

On continue avec la vue show définit dans le fichier resources/views/restaurants/show.blade.php

<x-layout>
    <x-slot:title>{{ $restaurant->name }}</x-slot:title>

    <h2>
        <a href="{{ route('restaurants.index') }}">Restaurants</a> / {{ $restaurant->name }}
    </h2>
    <div style="margin-bottom: 1rem">
        <a href="{{ route('restaurants.edit', $restaurant) }}">Editer</a> |
        <form style="display: inline-block" action="{{ route('restaurants.destroy', $restaurant) }}" method="POST">
            @csrf
            @method('delete')
            <a href="{{ route('restaurants.destroy', $restaurant) }}" onclick="event.preventDefault(); this.closest('form').submit();">Supprimer</a>
        </form>
    </div>
    <ul>
        <li>Type : {{ $restaurant->type }}</li>
        <li>Adresse : {{ $restaurant->address }}</li>
    </ul>
</x-layout>

La particularité de cette page réside dans le fait qu’on y définit un formulaire pour la suppression du restaurant ciblé. Pourquoi ? Parce que le verbe qu’on a définit dans la route de suppression et qui respecte le standard est delete.

Cela nous permet d’introduire deux nouveautés. La première c’est la directive @csrf qui créer un champ caché qui contient le jeton qui validera notre formulaire. La seconde c’est l’appel à @method('delete) qui permet de spécifier à Laravel que le verbe utilisé est bien delete car en html on ne peut définir uniquement que la method en GET ou en POST dans un formulaire.

Le jeton CSRF permet de s’assurer que le site qui a émit la requête est bien celui de notre application.

Création des composants du formulaire

La création de petit composant réutilisable permet de vraiment gagner du temps et d’éviter les oublis lors de modifications de style à apporter de manière globale à l’application.

Nos formulaires de création et d’édition d’un restaurant vont contenir des champs de type texte, on va donc créer un premier composant nommé input dans le dossier resources/views/components :

<input {{ $attributes }}/>

La variable $attributes contient les attributs définit lors de l’appel du composant, exemple :

<x-input id="name" name="name" type="text" :value="old('name')"/>

A noter qu’un attribut préfixé de : permet l’injection de code PHP, utile dans notre cas pour appeler la fonction old().

Un autre composant pertinent à créer est celui du libellé d’un champ, on va ainsi créer le fichier resources/views/components/label.blade.php :

<label {{ $attributes }}>
    {{ $slot }}
</label>

Que l’on va utiliser de la manière suivante :

<x-label for="name">Nom</x-label>

Ainsi Nom viendra remplacer $slot et l’attribut for sera injecté dans la variable $attributes.

Création des vues d’écriture

Maintenant on a tous les éléments à notre disposition pour créer les formulaires.

On commence par le formulaire de création d’un restaurant qu’on va définir dans le fichier resources/views/restaurants/create.blade.php :

<x-layout>
    <x-slot:title>Créer un restaurant</x-slot:title>

    <h2 style="margin-bottom: 2rem">
        <a href="{{ route('restaurants.index') }}">Restaurants</a> / Créer un restaurant
    </h2>
    <form action="{{ route('restaurants.store') }}" method="POST">
        @csrf
        <div style="margin-bottom: 1rem">
            <x-label for="name">Nom</x-label>
            <x-input id="name" name="name" type="text" :value="old('name')"/>
        </div>
        <div style="margin-bottom: 1rem">
            <x-label for="type">Type</x-label>
            <x-input id="type" name="type" type="text" :value="old('type')"/>
        </div>
        <div style="margin-bottom: 1rem">
            <x-label for="type">Adresse</x-label>
            <x-input id="address" name="address" type="text" :value="old('address')"/>
        </div>
        <button type="submit">Enregistrer</button>
    </form>
</x-layout>

Ici, rien de nouveau à l’horizon si ce n’est l’utilisation de nos deux nouveaux composants x-label et x-input.

On termine avec notre formulaire d’édition d’un restaurant resources/views/restaurants/edit.blade.php :

<x-layout>
    <x-slot:title>Edition du restaurant {{ $restaurant->name }}</x-slot:title>

    <h2 style="margin-bottom: 2rem">
        <a href="{{ route('restaurants.index') }}">Restaurants</a> /
        <a href="{{ route('restaurants.show', $restaurant) }}">{{ $restaurant->name }} </a> /
        Edition
    </h2>
    <form action="{{ route('restaurants.update', $restaurant) }}" method="POST">
        @csrf
        @method('put')
        <div style="margin-bottom: 1rem">
            <x-label for="name">Nom</x-label>
            <x-input id="name" name="name" type="text" :value="old('name', $restaurant->name)"/>
        </div>
        <div style="margin-bottom: 1rem">
            <x-label for="type">Type</x-label>
            <x-input id="type" name="type" type="text" :value="old('type', $restaurant->type)"/>
        </div>
        <div style="margin-bottom: 1rem">
            <x-label for="type">Adresse</x-label>
            <x-input id="address" name="address" type="text" :value="old('address', $restaurant->address)"/>
        </div>
        <button type="submit">Enregistrer</button>
    </form>
</x-layout>

Pour cette vue, on définit le verbe put à travers la directive @method, car on respecte une nouvelle fois le standard, et on injecte en valeur par défaut dans les champs celles actuelles du restaurant.

Et voilà, l'ensemble de nos vues sont prêtes !

Les sources de ce tutoriel sont disponibles sur ce dépôt.

Dans le prochain épisode…

Nous avons parcouru l'ensemble de l’architecture MVC, il est temps de consolider notre application avec la validation des entrées du formulaire via les FormRequest !