Commentaires
On va commencer par gérer l'affichage dans notre dashboard. Je vais faire des choses vraiment très simples niveau design, le but est que nous nous concentrions sur l'utilisation de Laravel.

Arthur, l'apprenti développeurCompris !

L'accueil du dashboard


On va commencer par modifier l'accueil du dashboard. Pour cela, on va aller dans le fichier resources->views->dashboard.blade.php.

Arthur, l'apprenti développeurBlade ?
C'est le moteur de templates de Laravel. Au même titre que le framework Symfony a Twig. Blade fait le lien entre le contrôleur et les vues, gère les variables et le templating ;)

Le contenu de dashboard.blade.php est le suivant :

{"language":"application/x-httpd-php","content":"<x-app-layout>\n <x-slot name=\"header\">\n <h2 class=\"font-semibold text-xl text-gray-800 leading-tight\">\n {{ __('Dashboard') }}\n </h2>\n </x-slot>\n\n <div class=\"py-12\">\n <div class=\"max-w-7xl mx-auto sm:px-6 lg:px-8\">\n <div class=\"bg-white overflow-hidden shadow-sm sm:rounded-lg\">\n <div class=\"p-6 bg-white border-b border-gray-200\">\n You're logged in!\n </div>\n </div>\n </div>\n </div>\n</x-app-layout>","filename":"dashboard.blade.php"}

Arthur, l'apprenti développeurx-app-layout et x-slot ? Ce ne sont pas des balises HTML ça ?
En effet. Ces "balises" permettent de faire appel, dans ce cas, à un layout. C'est une syntaxe un peu particulière générée par Laravel Breeze, on ne peut pas faire ça tout le temps. C'est grâce aux View Composers. Depuis Laravel 8, on peut utiliser des layouts grâce aux "composants" et aux View Composers. On ne va pas s'attarder sur le sujet, on en aura pas besoin nous. Quand on fera notre propre layout dans la dernière partie, on verra la syntaxe par "héritage". Considérons donc simplement que ces balises permettent d'utiliser notre layout ! D'ailleurs, ce layout, c'est celui dans layouts->app.blade.php :

{"language":"application/x-httpd-php","content":"<!DOCTYPE html>\n<html lang=\"{{ str_replace('_', '-', app()->getLocale()) }}\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n\n <title>{{ config('app.name', 'Laravel') }}</title>\n\n <!-- Fonts -->\n <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap\">\n\n <!-- Styles -->\n <link rel=\"stylesheet\" href=\"{{ asset('css/app.css') }}\">\n\n <!-- Scripts -->\n <script src=\"{{ asset('js/app.js') }}\" defer></script>\n </head>\n <body class=\"font-sans antialiased\">\n <div class=\"min-h-screen bg-gray-100\">\n @include('layouts.navigation')\n\n <!-- Page Heading -->\n <header class=\"bg-white shadow\">\n <div class=\"max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8\">\n {{ $header }}\n </div>\n </header>\n\n <!-- Page Content -->\n <main>\n {{ $slot }}\n </main>\n </div>\n </body>\n</html>\n","filename":"app.blade.php"}

Arthur, l'apprenti développeurOula, y'a plein de trucs bizarres. C'est quoi tous ces trucs entre moustaches ? ({{ ... }})
Hé bien ça, c'est Blade ! C'est la syntaxe qu'utilise Blade pour afficher du contenu PHP. Décryptons un peu tout ça :

  • {{ str_replace('_', '-', app()->getLocale()) }} : ici, on utilise str_replace de PHP pour remplacer les éventuels _ par des - dans la chaine app()->getLocale(). app() est un helpeur qui permet d'accéder aux variables de configuration définies dans la fichier app.php. Ici, on va chercher la valeur de "locale". On l'avait remplacée par "fr" au début !

  • meta name="csrf-token" content="{{ csrf_token() }}" : je t'en avais parlé, il s'agit ici d'initialiser le TOKEN CSRF, une mesure de protection contre la faille du même nom

  • {{ config('app.name', 'Laravel') }} : ici on fait appel à un autre helpeur "config" qui va chercher dans le fichier de configuration spécifié la valeur de la donnée spécifiée. Si elle n'existe pas, on affiche une valeur par défaut, ici "Laravel". Dans notre cas, on va chercher dans le fichier de configuration app.php la valeur de la variable "name".

  • {{ asset('css/app.css') }} : le helpeur asset nous permet de charger les feuilles de style, images et js qu'on aura mis dans le dossier public ;). Ici on va chercher le fichier app.css dans le dossier ces du dossier public.

  • {{ $header }} : on affiche la variable nommée "header". Dans notre cas, header est en fait définie dans dashboard.blade.php grâce à x-slot name="header". Cette syntaxe, encore une fois, est très particulière, on la réutilisera pas. On la retrouve aussi avec {{ $slot }} qui affichera tout le reste de notre contenu dans dashboard.blade.php


Arthur, l'apprenti développeurOk, je commence à comprendre...
Retournons alors dans dashboard.blade.php. Tu as vu, on utilise {{ __('Dashboard') }}. On pourrait s'attendre à ce que cette portion de code affiche "Dashboard" sur notre page. Pourtant, c'est bien "Tableau de bord" qui est affiché. Tu saurais pourquoi ?

Arthur, l'apprenti développeurCe ne serait pas du aux fichiers qu'on a installés dans resources/lang au début ?
En partie ! En fait, quand tu utilises la syntaxe double underscore ( __('')), tu dis à Blade que tu veux afficher le mot entre guillemets dans la langue que tu as renseignée dans ton fichier de configuration app.php. Laravel va alors aller chercher si un fichier nommé LANGUE.json existe. Si c'est le cas, il va récupérer la valeur de la clé qui est ici le mot. Si tu regardes dans le fichier resources/lang/fr.json, tu as cette ligne :
"Dashboard": "Tableau de bord",
Bilan, on traduit "Dashboard" en "Tableau de bord".

Arthur, l'apprenti développeurCa rend un site multilingue assez facile à faire !
Oui. Bon, dans le cadre de notre projet, on ne va pas s'amuser à tout traduire et donc à tout compléter nos fichiers de langue, on va écrire en dur. Plus simple et suffisant pour nos besoins.

Arthur, l'apprenti développeurOk, maintenant que j'ai un peu mieux compris le fonctionnement de blade et compagnie, on peut commencer !
Dans ce cas je te propose de mettre dans le dashboard 3 liens :
- Gestion des utilisateurs
- Gestion des posts
- Gestion des commentaires signalés
{"language":"text/html","content":"<x-app-layout>\n <x-slot name=\"header\">\n <h2 class=\"font-semibold text-xl text-gray-800 leading-tight\">\n {{ __('Dashboard') }}\n </h2>\n </x-slot>\n\n <div class=\"py-12\">\n <div class=\"max-w-7xl mx-auto sm:px-6 lg:px-8\">\n <div class=\"bg-white overflow-hidden shadow-sm sm:rounded-lg\">\n <h3 class=\"text-3xl mx-4 my-4\">Les actions possibles</h3>\n <div class=\"p-6 bg-white border-b border-gray-200 text-center\">\n <a href=\"{{ route('users') }}\" class=\"inline-flex items-center px-6 py-4 border border-gray-400 shadow-sm text-base font-medium rounded-md text-gray-700 bg-white\">\n Gestion des utilisateurs\n </a>\n <a href=\"{{ route('posts.index') }}\" class=\"inline-flex items-center px-6 py-4 border border-gray-400 shadow-sm text-base font-medium rounded-md text-gray-700 bg-white\">\n Gestion des posts\n </a>\n <a href=\"{{ route('comments.index') }}\" class=\"inline-flex items-center px-6 py-4 border border-gray-400 shadow-sm text-base font-medium rounded-md text-gray-700 bg-white\">\n Gestion des commentaires\n </a>\n </div>\n </div>\n </div>\n </div>\n</x-app-layout>","filename":"dashboard.blade.php"}

Arthur, l'apprenti développeurC'est quoi route ?
Encore un helpeur... Ca nous permet de renseigner des liens internes à notre application via le nom des routes. Tu sais, quand on a fait :
{"language":"application/x-httpd-php","content":"<?php\nRoute::get('/users', [UsersController::class, 'index'])->middleware(['auth', 'admin'])->name('users');","filename":""}

On a donné le nom de "users" à la route. C'est ce nom que je réutilise. Laravel va alors transformer route('users') en monapplication.com/users. C'est bien d'utiliser les noms de routes car on est ainsi indépendant du nom de notre site et on peut changer l'URL à tout moment sans devoir changer toutes nos vues.
Voici ce que ça donne :


Et au clic sur un lien :


C'est donc le moment de créer notre première vue !

Notre première vue


L'erreur était assez explicite. On n'a pas encore créé le fichier auquel on fait appel dans notre contrôleur dans l'action index. On va donc la créer. Pour ça, pas d'artisan, il va falloir le faire à la main :p
On crée donc le dossier "users" dans resources/views. Et ensuite on crée le fichier index.blade.php. Je démarre avec ce contenu :
{"language":"text/html","content":"<x-app-layout>\n <x-slot name=\"header\">\n <h2 class=\"font-semibold text-xl text-gray-800 leading-tight\">\n Gestion des utilisateurs\n </h2>\n </x-slot>\n\n <div class=\"py-12\">\n <div class=\"max-w-7xl mx-auto sm:px-6 lg:px-8\">\n <div class=\"bg-white overflow-hidden shadow-sm sm:rounded-lg\">\n <h3 class=\"text-3xl mx-4 my-4\">Les utilisateurs du site</h3>\n \n </div>\n </div>\n </div>\n</x-app-layout>\n","filename":"index.blade.php"}

Arthur, l'apprenti développeurSi je comprends bien, tu refais appel au layout de dashboard et tu affiches 2 titres ?
C'est tout à fait ça tu as bien compris.
Bon, le but va être d'afficher la liste de tous nos utilisateurs. Pour cela on va utiliser un tableau et mettre une ligne par user. On va donc devoir faire un "foreach users" en gros.

Arthur, l'apprenti développeurJ'imagine que Blade peut nous faire ça !
Exactement, avec une fonction nommée @foreach. On va faire @foreach($users as $user). Comme en PHP !
Voici ce que je te propose. Tu remarqueras que j'affiche les variables avec mes moustaches {{ }}. A l'intérieur on peut mettre n'importe quelle ligne PHP classique qui affiche du contenu, on peut donc mettre une ternaire. Enfin, tu remarqueras également que j'utilise la route() en passant un paramètre à la route qui n'est rien d'autre que $user, pour l'implicit binding !

{"language":"text/html","content":"<x-app-layout>\n <x-slot name=\"header\">\n <h2 class=\"font-semibold text-xl text-gray-800 leading-tight\">\n Gestion des utilisateurs\n </h2>\n </x-slot>\n\n <div class=\"py-12\">\n <div class=\"max-w-7xl mx-auto sm:px-6 lg:px-8\">\n <div class=\"bg-white overflow-hidden shadow-sm sm:rounded-lg\">\n <h3 class=\"text-3xl mx-4 my-4\">Les utilisateurs du site</h3>\n <div class=\"flex flex-col\">\n <div class=\"-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n <div class=\"py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8\">\n <div class=\"shadow overflow-hidden border-b border-gray-200 sm:rounded-lg\">\n <table class=\"min-w-full divide-y divide-gray-200\">\n <thead class=\"bg-gray-50\">\n <tr>\n <th scope=\"col\" class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">\n Nom\n </th>\n <th scope=\"col\" class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">\n Email\n </th>\n <th scope=\"col\" class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">\n Role\n </th>\n <th scope=\"col\" class=\"relative px-6 py-3\">\n <span class=\"sr-only\">Modifier</span>\n </th>\n </tr>\n </thead>\n <tbody class=\"bg-white divide-y divide-gray-200\">\n @foreach($users as $user)\n <tr>\n <td class=\"px-6 py-4 whitespace-nowrap\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ $user->name }}\n </div>\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ $user->email }}\n </div>\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ $user->admin ? 'Administrateur' : 'Utilisateur' }}\n </div>\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap text-right text-sm font-medium\">\n <a href=\"{{ route('users.edit', $user) }}\" class=\"text-indigo-600 hover:text-indigo-900\">Modifier</a>\n </td>\n </tr>\n @endforeach\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</x-app-layout>","filename":"index.blade.php"}

Médite bien ce code !

Arthur, l'apprenti développeurJe le regarderai bien, mais je crois que ce n'est pas très dur à comprendre ! Par contre je suis en train de penser à un truc... On a mis un middleware sur les routes users.edit et users.update pour que seules les personnes authentifiées y ait accès. Mais... Une fois connecté, on peut accéder à cette page et indiquer n'importe quel id user dans l'URL, et donc potentiellement modifier le profil de quelqu'un d'autre que nous :o
Félicitations ! Il faut en effet corriger ça. On pourrait utiliser des policies https://laravel.com/docs/8.x/authorization pour palier à ce problème, mais on va rester dans des choses simples pour ce cours. Je te propose simplement de modifier les contrôleurs comme suit :
{"language":"application/x-httpd-php","content":"<?php\npublic function edit(User $user) {\n if($user->id == request()->user()->id) {\n abort(403);\n }\n \treturn view('users.edit', compact('user'));\n }","filename":""}

Arthur, l'apprenti développeurOn réutilise request()->user(), mais oui !
Tout à fait ! Bon, il nous reste quand même à autoriser l'administrateur à modifier les profils. Voici le contrôleur UsersController modifié en conséquence.

{"language":"application/x-httpd-php","content":"<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\nuse App\\Models\\User;\n\nclass UsersController extends Controller\n{\n public function index() \n {\n \t$users = User::all();\n \treturn view('users.index', compact('users'));\n }\n\n public function show(User $user) {\n \treturn view('users.show', compact('user'));\n }\n\n public function edit(User $user) {\n $this->isAbleToEdit($user);\n \treturn view('users.edit', compact('user'));\n }\n\n public function update(Request $request, User $user) {\n $this->isAbleToEdit($user);\n $validatedData = $request->validate([\n 'name' => ['required', 'min:2', 'max:50'],\n 'email' => 'required|email',\n ]);\n\n $user->update($validatedData);\n\n return redirect()->back()->with('success', 'Les informations ont bien été modifiées');\n }\n\n public function destroy(User $user) {\n \t$user->delete();\n \treturn redirect()->back()->with('success', 'L\\'utilisateur a bien été supprimé');\n }\n\n private function isAbleToEdit(User $user) {\n if($user->id == request()->user()->id and !request()->user()->admin) {\n abort(403);\n }\n }\n}","filename":"UsersController.php"}

Arthur, l'apprenti développeurIl faudrait faire pareil pour l'édition des posts et des commentaires !
Exactement, je te laisse modifier les contrôleurs !

J'ai terminé cette partie
Demander de l'assistance