
J'avais commencé dans un ancien article à montrer comment créer une simple application Laravel 9 en détaillant toutes les étapes. Une application qui s'adresse donc aux débutants qui désirent découvrir ce framework, et peut-être aux moins débutants qui aimeraient se rafraichir un peu les idées ! Comme les choses avaient peu évoluées avec Laravel 10 et 11, je vous avais proposé des versions actualisées. Je continue sur cette lancée avec cette nouvelle version à l'occasion de la sortie de Laravel 12, toujours dans le même esprit de découverte du framework au travers d'une application simple, mais suffisamment étoffée, pour explorer les éléments essentiels de ce magnifique framework.
On va créer un simple gestionnaire de tâches. Vous pouvez télécharger le code final de l'article.
Les prérequis
Pour utiliser Laravel, et suivre cet article, vous aurez besoin des éléments suivants :
- Serveur PHP : assurez-vous que votre serveur est équipé de PHP avec au minimum la version 8.2. Laravel nécessite une version récente de PHP pour fonctionner correctement.
- Extensions PHP : plusieurs extensions PHP doivent être activées pour que Laravel fonctionne correctement. Voici une liste des extensions couramment requises :
- OpenSSL : pour les opérations de cryptage et de décryptage.
- PDO : pour l'accès aux bases de données.
- Mbstring : pour la manipulation des chaînes de caractères multioctets.
- Tokenizer : pour l'analyse syntaxique des fichiers PHP.
- XML : pour la manipulation des fichiers XML.
- Ctype : pour les fonctions de manipulation de caractères.
- JSON : pour la manipulation des données JSON.
- BCMath : pour les opérations mathématiques de haute précision.
Vous pouvez trouver tout ça facilement sur un serveur local comme WAMPP ou XAMPP, mais franchement si vous ne voulez pas vous compliquer la vie, utilisez Laragon !
Vous aurez aussi besoin de Composer pour gérer les librairies PHP. Enfin pour le frontend il vous faudra node.js. Vous avez tout ça ? Alors c'est parti !
Une autre solution complète pour Windows consiste à utiliser le nouveau Laravel Herd.
Installation avec Laravel Installer
Une solution classique pour installer Laravel, consiste à utiliser l’installeur officiel. Il faut commencer par installer globalement l’installeur avec Composer :
composer global require laravel/installer
L'avantage de l'utilisation de Laravel Installer est qu'on va nous proposer pas mal d'options. En particulier la possibilité d'utiliser un kit de démarrage (starter kit). Les kits de démarrage vous offrent un point de départ pour construire votre application Laravel. Ils incluent les routes, contrôleurs et vues nécessaires pour enregistrer et authentifier les utilisateurs de votre application. En d'autres termes, ils vous fournissent une base solide pour gérer l'inscription et la connexion des utilisateurs, vous permettant ainsi de vous concentrer sur le développement des fonctionnalités spécifiques à votre projet sans avoir à repartir de zéro pour ces aspects essentiels.
Il existe actuellement 3 kit :
- React
- Vue
- Livewire
Pour notre projet on ne va pas utiliser d'autentification et donc faire une installation simplifiée pour ne pas alourdir inutilement le projet.
On commence l'installation :
laravel new todolist12
On tombe sur une première question :
Là on choisit none. Après quelques minutes d'installation vous avez cette question :
On choisit la première option sqlite qui est l'option par défaut.
Vous avez ensuite une dernière question :
Répondez yes. Et c'est terminé ! Vous arrivez sur la page d'accueil de Laravel :
Base de données
Les migrations
Laravel dispose d'un outil de migration pour créer des tables, les modifier, créer des index...
On trouve ces migrations dans le dossier database :
On y trouve ici 3 fichiers de migration :
- pour la table users
- pour la table cache_table
- pour la table jobs_table
Si on regarde un peu le code pour users on a une fonction up :
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
C'est ici qu'on a le code pour créer la table et ses colonnes. Je ne vais pas entrer dans le détail mais le code est explicite.
Pour créer les tables à partir de cette migration on utilise Artisan. Mais l'installeur de Laravel, merci à lui, a fait les migrations pour nous pendant le processus d'installation :
Les tables existent donc déjà dans notre base SQLite. Mais nous n'allons pas utiliser ces tables pour notre projet en nous passant de l'authentification.
Les données
Il est maintenant temps de se poser la question des données nécessaires pour notre application. Pour chaque tâche on va avoir :
- un titre ("Tondre la pelouse")
- un texte de détail ("Ne pas oublier de demander la tondeuse au voisin la veille")
- une date de création
- une date de modification
- un état (a priori deux : "à faire" et "fait")
On va donc créer une table pour mémoriser tout ça. On a vu qu'avec Laravel on utilise une migration. D'autre part, Laravel est équipé d'un ORM efficace : Eloquent. Chaque table est représentée par une classe qui permet de manipuler les données. On dispose ainsi d'un modèle pour chaque table à manipuler. On va demander à Artisan de créer à la fois une table et son modèle Eloquent associé :
php artisan make:model Task -m
On trouve le modèle ici :
On a déjà le modèle par défaut User pour gérer les données de la table users. La migration pour la table tasks a été créée ici :
Par défaut on a ce code :
public function up(): void
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
On a :
- une clé id
- deux colonnes (created_at et updated_at) créées par la méthode timestamps.
On ajoute les autres colonnes nécessaires pour notre projet :
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->text('detail');
$table->boolean('state')->default(false);
});
Et on lance la migration :
On dispose à présent de la table tasks dans notre base SQLite.
Le contrôleur et les routes
Laravel est basé sur le modèle MVC :
- Modèle : c'est Eloquent qui se charge de cet aspect, et on a créé un modèle (Task) pour nos tâches,
- Vue : on va devoir en créer les vues pour nos tâches,
- Contrôleur : c'est le chef d'orchestre de l'application, on va créer à présent un contrôleur pour gérer toutes les actions nécessaires pour les tâches.
php artisan make:controller TaskController --resource
On trouve ce contrôleur ici :
C'est un contrôleur de ressource, ce qui signifie qu'il est déjà équipé de 7 fonctions pour les actions suivantes :
Verbe | URI | Action | Route |
---|---|---|---|
GET | /tasks |
index | tasks.index |
GET | /tasks/create |
create | tasks.create |
POST | /tasks |
store | tasks.store |
GET | /tasks/{task} |
show | tasks.show |
GET | /tasks/{task}/edit |
edit | tasks.edit |
PUT/PATCH | /tasks/{task} |
update | tasks.update |
DELETE | /tasks/{task} |
destroy | tasks.destroy |
On crée aussi les routes pour accéder à ces actions dans le fichier routes/web.php :
use App\Http\Controllers\TaskController;
Route::resource('tasks', TaskController::class);
Si vous utilisez la commande php artisan route:list, vous visualisez toutes les routes de l'application, et en particulier les 7 pour le contrôleur que nous venons de créer:
Maintenant que tout ça est en place on va coder ces actions et créer les vues correspondantes !
Organisation des vues
Laravel propose plusieurs façon d'organiser les vues, on peut les combiner avec un simple héritage ou utiliser des composants. Cette seconde possibilité est en fait la plus utilisée désormais, alors on va l'adopter pour notre projet.
On va avoir plusieurs vues qui auront un code de base commun. Ce code de base sera placé dans un composant layout. Commençons par le créer :
php artisan make:component layout --view
Vous le trouvez ici :
La vue welcome est celle qui correspond à la page par défaut quand vous installez Laravel, et on ne l'utilisera pas.
Pour notre layout on prévoit ce code :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mes tâches</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-gray-100">
<div class="container mx-auto p-4 max-w-4xl">
<h1 class="text-2xl font-bold mb-4">{{ $title }}</h1>
{{ $slot }}
</div>
</body>
</html>
Le $slot affiche le contenu inséré dans cette section depuis une vue enfant. C'est une fonctionnalité de Blade qui permet d'injecter du contenu dynamique.
Laravel utilise Vite pour inclure les fichiers CSS et JavaScript compilés. Vite est un outil de construction qui optimise le chargement des ressources.
Lors de l'installation on a eu la commande :
npm run build
Cette commande a permis de construire les fichiers de ressources (css et javascript). Mais si vous ajoutez par la suite des éléments Tailwind qui n'étaient pas présents au départ, ils ne se retrouveront pas dans les ressources. Il faudrait relancer la commande, ce qui seraient laborieux. C'est pour cette raison que lors du développement on utlise plutôt la commande :
npm run dev
On aura de cette façon une construction "à la volée" dès qu'on ajoute des éléments.
Créer une tâche
Le formulaire
Pour la création d'une tâche on va avoir besoin d'un formulaire. On crée un dossier tasks et la vue create :
Avec ce code :
<x-layout>
<x-slot:title>
Créer une tâche
</x-slot:title>
<!-- Message de réussite -->
@if (session()->has('message'))
<div class="mt-3 mb-4 list-disc list-inside text-sm text-green-600">
{{ session('message') }}
</div>
@endif
<form action="{{ route('tasks.store') }}" method="post">
@csrf
<!-- Titre -->
<div class="mb-4">
<label for="title" class="block text-gray-700">Titre :</label>
<input type="text" id="title" name="title" class="w-full px-3 py-2 border rounded" value="{{ old('title') }}" required>
@error('title')
<div class="mt-3 mb-4 list-disc list-inside text-sm text-red-600">
{{ $message }}
</div>
@enderror
</div>
<!-- Détail -->
<div class="mb-4">
<label for="detail" class="block text-gray-700">Détail :</label>
<textarea id="detail" name="detail" class="w-full px-3 py-2 border rounded" required>{{ old('detail') }}</textarea>
@error('detail')
<div class="mt-3 mb-4 list-disc list-inside text-sm text-red-600">
{{ $message }}
</div>
@enderror
</div>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">Envoyer</button>
</form>
</x-layout>
Il y a beaucoup à dire sur ce code mais je ne vais pas entrer dans les détails. Le formulaire est défini avec ce code :
<form action="{{ route('tasks.store') }}" method="post">
On utilise l'helper route qui, à partir du nom de la route, génère l'url. Pour insérer des éléments avec PHP on utilise des accolades.
On a ensuite cette commande Blade :
@csrf
On demande ici à Blade d'insérer un token dans un champ caché qui va permettre à Laravel de contrer les attaques CSRF, le code généré ressemble à ça :
<input type="hidden" name="_token" value="sUTuW5dYrt2l2iPgAJ5EVXn5UwMjEGFLAZaH4jHz">
C'est automatique et on n'a pas besoin de s'en préoccuper ensuite. Un middleware se charge à l'arrivée de ce contrôle de sécurité.
On va compléter le code de la fonction create du contrôleur TaskController pour appeler la vue :
...
use Illuminate\View\View;
class TaskController extends Controller
{
...
public function create(): View
{
return view('tasks.create');
}
Maintenant avec l'url todolist12.oo/tasks/create on obtient la page avec le formulaire :
J'ai utilisé les classes de Tailwind puisqu'il a déjà été chargé par Laravel.
La soumission
Pour créer effectivement la tâche, on va devoir gérer la soumission du formulaire dans la méthode store du contrôleur :
use Illuminate\Http\RedirectResponse;
use App\Models\Task;
class TaskController extends Controller
{
...
public function store(Request $request): RedirectResponse
{
$data = $request->validate([
'title' => 'required|max:100',
'detail' => 'required|max:500',
]);
$task = new Task;
$task->title = $request->title;
$task->detail = $request->detail;
$task->save();
return back()->with('message', "La tâche a bien été créée !");
}
On commence par vérifier les entrées avec la validation. Les deux champs sont requis et on vérifie une longueur maximale.
Ensuite on utilise Eloquent pour créer la tâche. Pour finir on renvoie dans la vue. Vous pouvez vérifier que la validation fonctionne :
Pour le moment le texte de l'erreur est en anglais, on va s'en occuper plus loin.
Si la validation est bonne, la tâche est créée, et on retourne la même vue (back) mais cette fois on flashe une information en session (ce qui signifie qu'elle ne sera valable que pour la prochaine requête) avec with :
return back()->with('message', "La tâche a bien été créée !");
Dans la vue on vérifie s'il y a une information en session et si c'est le cas on l'affiche :
@if (session()->has('message'))
<div class="mt-3 mb-4 list-disc list-inside text-sm text-green-600">
{{ session('message') }}
</div>
@endif
Les erreurs en français
Par défaut, les messages d'erreur sont en anglais. Pour avoir ces textes en français, vous devez utiliser le package ici. Dans un premier temps, changez cette ligne dans le fichier .env :
APP_LOCALE=fr
Puis pour faire les choses simplement, faites cette installation :
composer require laravel-lang/common
Puis faites un update :
php artisan lang:update
Vous devriez à présent avoir vos erreurs en français :
DRY
Il y a un certain nombre de bonnes pratique lorsqu'on code, la première étant de ne jamais répéter du code (Don't Repeat Yourself). Si on regarde le code de notre vue de création de tâches, on voit quelques répétitions.
Les erreurs de validation
Prenons l'exemple des erreurs de validation. Nous avons pour nos deux contrôles un code pratiquement identique :
@error('title')
<div class="mt-3 mb-4 list-disc list-inside text-sm text-red-600">
{{ $message }}
</div>
@enderror
</div>
...
@error('detail')
<div class="mt-3 mb-4 list-disc list-inside text-sm text-red-600">
{{ $message }}
</div>
@enderror
Il est donc judicieux de créer un composant dans ce cas :
php artisan make:component error --view
Avec ce code :
@error($field)
<div class="mt-3 mb-4 list-disc list-inside text-sm text-red-600">
{{ $message }}
</div>
@enderror
Il n'y a plus qu'à substituer dans le formulaire :
<!-- Titre -->
<div class="mb-4">
<label for="title" class="block text-gray-700">Titre :</label>
<input type="text" id="title" name="title" class="w-full px-3 py-2 border rounded" value="{{ old('title') }}" required>
<x-error field="title" />
</div>
<!-- Détail -->
<div class="mb-4">
<label for="detail" class="block text-gray-700">Détail :</label>
<textarea id="detail" name="detail" class="w-full px-3 py-2 border rounded" required>{{ old('detail') }}</textarea>
<x-error field="detail" />
</div>
On obtient un fonctionnement identique avec du code plus léger et clair.
Le label
On peut faire pareil pour le label :
php artisan make:component label --view
Avec ce code :
<label for="{{ $for }}" class="block text-gray-700">{{ $label }}</label>
Et dans le formulaire :
<!-- Titre -->
<div class="mb-4">
<x-label for="title" label="Titre :" />
<input type="text" id="title" name="title" class="w-full px-3 py-2 border rounded" value="{{ old('title') }}" required>
<x-error field="title" />
</div>
<!-- Détail -->
<div class="mb-4">
<x-label for="detail" label="Détail :" />
<textarea id="detail" name="detail" class="w-full px-3 py-2 border rounded" required>{{ old('detail') }}</textarea>
<x-error field="detail" />
</div>
Modifier une tâche
Le formulaire
Pour la modification d'une tâche on a besoin d'un formulaire. On crée la vue edit :
Évidemment, cette vue va beaucoup ressembler à celle de la création, mais il va falloir renseigner les deux champs, et on va ajouter la possibilité de modifier l'état :
<x-layout>
<x-slot:title>
Modifier une tâche
</x-slot:title>
<!-- Message de réussite -->
@if (session()->has('message'))
<div class="mt-3 mb-4 list-disc list-inside text-sm text-green-600">
{{ session('message') }}
</div>
@endif
<form action="{{ route('tasks.update', $task->id) }}" method="post">
@csrf
@method('put')
<!-- Titre -->
<div class="mb-4">
<x-label for="title" label="Titre :" />
<input type="text" id="title" name="title" class="w-full px-3 py-2 border rounded" value="{{ old('title', $task->title) }}" required>
<x-error field="title" />
</div>
<!-- Détail -->
<div class="mb-4">
<x-label for="detail" label="Détail :" />
<textarea id="detail" name="detail" class="w-full px-3 py-2 border rounded" required>{{ old('detail', $task->detail) }}</textarea>
<x-error field="detail" />
</div>
<!-- Tâche accomplie -->
<div class="mb-4">
<input id="state" type="checkbox" class="w-4 h-4 px-3 py-2 border rounded" name="state" @if(old('state', $task->state)) checked @endif>
<span class="text-gray-700">{{ __('Tâche accomplie') }}</span>
</div>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">Envoyer</button>
</form>
</x-layout>
Dans la déclaration du formulaire on a changé l'url :
<form action="{{ route('tasks.update', $task->id) }}" method="post">
On précise la route, et il faut ajouter l'identifiant de la tâche à modifier ($task->id). Remarquez que la route attend une méthode PUT, mais que là on déclare une méthode POST. C'est parce que les navigateurs gèrent très mal ce genre de méthode, alors on déclare un POST, mais après on précise qu'on veut un PUT :
@method('put')
Cela crée un champ caché qui va servir à Laravel pour savoir de quelle méthode il s'agit :
<input type="hidden" name="_method" value="put">
Pour le reste, ça ne change pas beaucoup de la création, sauf la case à cocher ajoutée. Dans le contrôleur on appelle la vue :
public function edit(Task $task): View
{
return view('tasks.edit', compact('task'));
}
Remarquez le paramètre qui est du type du modèle Task. C'est une façon de dire à Laravel : le paramètre transmis est un nombre mais en fait c'est l'identifiant d'une instance de Task. Du coup, Eloquent peut aller chercher dans la table la tâche correspondante. Il suffit ensuite de transmettre ça à la vue.
Maintenant, avec une url de la forme todolist12.oo/tasks/1/edit on atteint le formulaire.
La soumission
Pour modifier effectivement la tâche, on doit gérer la soumission du formulaire dans la méthode update du contrôleur :
public function update(Request $request, Task $task): RedirectResponse
{
$data = $request->validate([
'title' => 'required|max:100',
'detail' => 'required|max:500',
]);
$task->title = $request->title;
$task->detail = $request->detail;
$task->state = $request->has('state');
$task->save();
return back()->with('message', "La tâche a bien été modifiée !");
}
On a la même validation que pour la création. D'ailleurs, il faudrait pour bien faire, mutualiser ce code pour éviter cette redondance qui n'est jamais une bonne chose (principe DRY). Laravel dispose d'une stratégie élégante pour la validation avec les Form Request, vous pouvez trouver les détails dans la documentation.
On met à jour les valeurs de la tâche. Pour la case à cocher, il faut savoir qu'on ne retrouve une valeur que si elle est cochée. Donc on vérifie si la valeur existe pour mettre à jour dans la table.
Voir une tâche
On va partir du principe qu'on aura un tableau avec juste le titre des tâches et pas le détail, il faut donc prévoir de pouvoir afficher chaque tâche.
On crée la vue :
Avec ce code :
<x-layout>
<x-slot:title>
Voir une tâche
</x-slot:title>
<div class="max-w-2xl mx-auto bg-white shadow-md rounded-lg p-6 space-y-6">
<div class="border-b pb-4">
<h3 class="font-semibold text-xl text-gray-800">Titre</h3>
<p class="text-gray-600 mt-2">{{ $task->title }}</p>
</div>
<div class="border-b pb-4">
<h3 class="font-semibold text-xl text-gray-800">Détail</h3>
<p class="text-gray-600 mt-2">{{ $task->detail }}</p>
</div>
<div class="border-b pb-4">
<h3 class="font-semibold text-xl text-gray-800">Etat</h3>
<p class="text-gray-600 mt-2">
@if($task->state)
<span class="text-green-600">La tâche a été accomplie !</span>
@else
<span class="text-red-600">La tâche n'a pas encore été accomplie.</span>
@endif
</p>
</div>
<div class="border-b pb-4">
<h3 class="font-semibold text-xl text-gray-800">Date de création</h3>
<p class="text-gray-600 mt-2">{{ $task->created_at->format('d/m/Y') }}</p>
</div>
@if(!$task->created_at->isSameDay($task->updated_at))
<div>
<h3 class="font-semibold text-xl text-gray-800">Dernière modification</h3>
<p class="text-gray-600 mt-2">{{ $task->updated_at->format('d/m/Y') }}</p>
</div>
@endif
</div>
</x-layout>
On complète le contrôleur :
public function show(Task $task): View
{
return view('tasks.show', compact('task'));
}
Et avec une url de la forme todolist12.oo/tasks/1 on affiche les éléments d'une tâche :
On n'affiche la date de mise à jour (en fait le jour) que si elle est différente de celle de la création.
Liste des tâches
Maintenant qu'on sait créer, modifier et afficher des tâches, on va voir comment en afficher la liste, en prévoyant des boutons pour les différentes actions, ainsi qu'un bouton pour ouvrir le formulaire de création d'une tâche.
Au niveau du contrôleur on récupére toutes les tâches et on les envoie dans une vue :
public function index(): View
{
$tasks = Task::all();
return view('tasks.index', compact('tasks'));
}
Comme il n'y aura pas de très nombreuses tâches, on ne prévoie pas de pagination, mais Laravel sait très bien s'occuper de ça également.
On ajoute un composant pour les boutons dans la liste :
Avec ce code :
<a
role="button"
{{ $attributes->merge([
'class' => 'inline-flex items-center px-2 py-1 rounded-md font-semibold text-xs uppercase tracking-widest transition ease-in-out duration-150 focus:outline-none focus:ring ring-gray-300 disabled:opacity-25 ' .
($attributes->get('color') ?? 'bg-gray-800 border-transparent text-white hover:bg-gray-700 active:bg-gray-900 focus:border-gray-900') .
($attributes->get('delete-cursor') ? ' cursor-not-allowed' : '')
]) }}
>
{{ $slot }}
</a>
On crée la vue :
Avec ce code :
<x-layout>
<x-slot:title>
Liste des tâches
</x-slot:title>
<div class="container flex justify-center mx-auto relative">
<div class="flex flex-col w-full">
<div class="border-b border-gray-200 shadow overflow-x-auto pt-6">
<div class="flex justify-end mb-4">
<x-link-button href="{{ route('tasks.create') }}" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Ajouter une tâche
</x-link-button>
</div>
<table class="min-w-full bg-white">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-2 text-xs text-gray-500">#</th>
<th class="px-4 py-2 text-xs text-gray-500">Titre</th>
<th class="px-4 py-2 text-xs text-gray-500">Etat</th>
<th class="px-4 py-2 text-xs text-gray-500 text-center">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@foreach($tasks as $task)
<tr class="whitespace-nowrap">
<td class="px-4 py-4 text-sm text-gray-500">{{ $task->id }}</td>
<td class="px-4 py-4 text-sm font-medium text-gray-900">{{ $task->title }}</td>
<td class="px-4 py-4">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $task->state ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
{{ $task->state ? 'Effectuée' : 'A faire' }}
</span>
</td>
<td class="px-4 py-4 flex justify-center space-x-2">
<x-link-button href="{{ route('tasks.show', $task->id) }}" class="text-blue-600 hover:text-blue-400">
Voir
</x-link-button>
<x-link-button href="{{ route('tasks.edit', $task->id) }}" class="text-yellow-600 hover:text-yellow-400">
Modifier
</x-link-button>
<x-link-button delete-cursor color="bg-red-600 hover:bg-red-400" onclick="event.preventDefault(); document.getElementById('destroy{{ $task->id }}').submit();">
Supprimer
</x-link-button>
<form id="destroy{{ $task->id }}" action="{{ route('tasks.destroy', $task->id) }}" method="POST" style="display: none;">
@csrf
@method('DELETE')
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</x-layout>
Et cet aspect (j'ai un peu peaufiné les styles) :
Les boutons permettent d'accéder aux tâches qu'on a codées précédemment, sauf la suppression. On code pour cela cette fonction dans le contrôleur :
public function destroy(Task $task): RedirectResponse
{
$task->delete();
return redirect()->route('tasks.index');;
}
Je n'ai pas prévu de boîte de dialogue d'avertissement avant la suppression, mais ça serait à ajouter dans une application réelle. Pour cette suppression, j'ai prévu un formulaire caché pour chaque tâche, et un peu de javascript pour la soumission. Ce n'est évidemment pas la seule façon de faire, mais ça ne concerne pas directement Laravel.
Les URLs en français
On a vu que pour la création, on utilise une url de la forme ...tasks/create, et pour la modification ...tasks/1/edit. Il serait plus élégant d'avoir des mots en français là aussi. On peut le réaliser en ajoutant ce code dans le fichier AppServiceProvider.php :
use Illuminate\Support\Facades\Route;
...
public function boot(): void
{
Route::resourceVerbs([
'edit' => 'modification',
'create' => 'creation',
]);
}
Maintenant, les urls sont de la forme ...tasks/creation et pour la modification ...tasks/1/modification.
Les tests
Laravel permet de faire facilement de tests. Il utilise Pest ou PHPUnit, et on trouve par défaut le fichier de configuration phpunit.xml à la racine. Par défaut, la base de donnée est celle définie dans le fichier .env. Vous pouvez utiliser sqlite en mémoire en décommentant ces lignes pour éviter d'impacter votre base de données avec les tests :
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
Les fichiers de test se trouvent dans le dossier tests :
Lancez les tests :
On voit qu'il y a déjà des tests. Voyons comment ils sont constitués en analysant par exemple la classe ExampleTest
class ExampleTest extends TestCase
{
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
On envoie une requête HTTP GET sur l'url "/". Le test consiste à vérifier (assertStatus) qu'on a bien une réponse 200.
Remarquez l'importance du libellé de la méthode (test_the_application_returns_a_successful_response) pour obtenir un texte explicite dans le test (the application returns a successful response).
Maintenant qu'on a vu le principe des tests, on a va en créer un pour notre application, par exemple la création d'une tâche. On crée d'abord la classe de test :
php artisan make:test CreateTaskTest
On ajoute cette fonction dans la classe :
class CreateTaskTest extends TestCase
{
use RefreshDatabase;
public function test_can_create_task()
{
$response = $this->post('/tasks', [
'title' => 'Ma nouvelle tâche',
'detail' => 'Tous les details de ma nouvelle tâche',
]);
$this->assertDatabaseHas('tasks', [
'title' => 'Ma nouvelle tâche'
]);
$this->get('/tasks')->assertSee('Ma nouvelle tâche');
}
}
On fait les tests suivants :
- la tâche est bien dans la table
- on trouve la tâche dans la liste des tâches
On peut tester ainsi tous les aspects de l'application, je vous renvoie à la documentation détaillée pour tous les détails.
Conclusion
J'espère que ce petit exemple pourra donner envie de découvrir ce framework. Il est à la fois très chargé pour un débutant et frustrant pour quelqu'un de plus avancé mais son seul objectif est de permettre la découverte de Laravel au travers d'un exemple léger mais réaliste.
Par bestmomo
Aucun commentaire