Laravel

Un framework qui rend heureux

Voir cette catégorie
Vers le bas
Voir cette série
Shop : l'administration
Samedi 1 février 2025 20:45

Maintenant que nous avons créé la partie visuelle de la boutique, autrement dénommée frontend, nous allons à présent nous consacrer à la partie cachée, l'administration, aussi dénommée backend. Nous allons conserver la même architecture avec MaryUi et Volt pour rester cohérent. On pourrait utiliser n'importe quel autre environnement et même passer par des solutions toutes prêtes comme Filament que j'aime bien. Cependant, il est bien plus pertinent d'un point de vue didactique de développer complètement cette partie.

Vous pouvez trouver le code dans ce dépôt Github.

Un middleware

Pour les besoins de l'administration, on aura souvent besoin de savoir si l'utilisateur connecté est administrateur pour filtrer les accès correspondants.

Un middleware dans Laravel est une couche intermédiaire qui traite les requêtes HTTP avant qu'elles n'atteignent les contrôleurs ou après qu'elles aient été traitées par les contrôleurs. Il permet d'exécuter des tâches spécifiques, comme l'authentification, la validation, la journalisation, ou la modification des requêtes et des réponses. Les middlewares sont utilisés pour centraliser et organiser le code qui doit être exécuté à chaque requête, ce qui facilite la maintenance et la réutilisation du code.

On commence par ajouter une méthode dans le modèle User :

public function isAdmin(): bool
{
    return 'admin' === $this->role;
}

On crée un middleware pour sélectionner les administrateurs :

php artisan make:middleware IsAdmin

public function handle(Request $request, Closure $next): Response
{
    if (!auth()->user()->isAdmin()) {
        abort(403);
    }
    
    return $next($request);
}

Le layout

Au niveau du layout, nous n'allons pas avoir les mêmes besoins que pour l'authentification et l'affichage de la boutique. On va donc créer un layout spécifique pour cette partie. En particulier, on va se contenter d'une barre latérale de navigation.

La barre de navigation

On crée le composant pour la barre de navigation :

php artisan make:volt admin/sidebar --class

Avec ce code :

<?php

use Illuminate\Support\Facades\{Auth, Session};
use Livewire\Volt\Component;

new class() extends Component
{
	public function logout(): void
	{
		Auth::guard('web')->logout();

		Session::invalidate();
		Session::regenerateToken();

		$this->redirect('/');
	}
}; ?>

<div>
    <x-menu activate-by-route>
        <x-menu-separator />
        <x-list-item :item="Auth::user()" value="name" sub-value="email" no-separator no-hover class="-mx-2 !-my-2 rounded">
            <x-slot:actions>
                <x-button icon="o-power" wire:click="logout" class="btn-circle btn-ghost btn-xs"
                    tooltip-left="{{ __('Logout') }}" no-wire-navigate />
            </x-slot:actions>
        </x-list-item>
        <x-menu-separator />
        <x-menu-item title="{{ __('Dashboard') }}" icon="s-building-office-2" link="{{ route('admin') }}" />
        <x-menu-item icon="m-arrow-right-end-on-rectangle" title="{{ __('Go on store') }}" link="/" />
        <x-menu-item>
            <x-theme-toggle />
        </x-menu-item>
    </x-menu>
</div>

Vous avez sans doute remarqué qu'on a une route que nous n'avons pas encore créée, mais ça ne va pas tarder.

Le layout

Maintenant, nous pouvons ajouter notre layout :

Avec ce code :

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ isset($title) ? $title . ' | ' . config('app.name') : config('app.name') }}</title>

    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

<body class="min-h-screen font-sans antialiased bg-base-200/50 dark:bg-base-200">

    {{-- MAIN --}}
    <x-main full-width>

        {{-- SIDEBAR --}}
        <x-slot:sidebar drawer="main-drawer" collapsible class="bg-base-100">
            <livewire:admin.sidebar />
        </x-slot:sidebar>

        <x-slot:content>
            <!-- Drawer toggle for "main-drawer" -->
            <label for="main-drawer" class="mr-3 lg:hidden">
                <x-icon name="o-bars-3" class="cursor-pointer" />
            </label>
            {{ $slot }}
        </x-slot:content>

    </x-main>

    {{--  TOAST area --}}
    <x-toast />

</body>

</html>

Un composant pour le tableau de bord

Il ne nous manque plus que le composant pour notre tableau de bord :

php artisan make:volt admin/index --class

Ajoutez ce code :

<?php

use App\Models\{ Order, Product, User };
use Livewire\Attributes\{Layout, Title};
use Livewire\Volt\Component;

new 
#[Title('Dashboard')] 
#[Layout('components.layouts.admin')] 
class extends Component
{

    public bool $openGlance = true;
 
    public function with(): array
	{
		return [
			'productsCount' => Product::count(),
			'ordersCount'   => Order::whereRelation('state', 'indice', '>', 3)
                                    ->whereRelation('state', 'indice', '<', 6)
                                    ->count(),
			'usersCount'    => User::count(),
		];
	}

}; ?>

<div>
    <x-collapse wire:model="openGlance" class="shadow-md">
        <x-slot:heading>
            @lang('In a glance')
        </x-slot:heading>
        <x-slot:content class="flex flex-wrap gap-4">
            <a href="/" class="flex-grow">
                <x-stat 
                    title="{{ __('Active products') }}" 
                    description="" 
                    value="{{ $productsCount }}" 
                    icon="s-shopping-bag"
                    class="shadow-hover" />
            </a>
            <a href="/" class="flex-grow">
                <x-stat 
                    title="{{ __('Successful orders') }}" 
                    description="" 
                    value="{{ $ordersCount }}" 
                    icon="s-shopping-cart"
                    class="shadow-hover" />
            </a>
            <a href="/" class="flex-grow">
                <x-stat 
                    title="{{ __('Customers') }}" 
                    description="" 
                    value="{{ $usersCount }}" 
                    icon="s-user"
                    class="shadow-hover" />
            </a>
        </x-slot:content>
    </x-collapse>
</div>

On ajoute la route :

use App\Http\Middleware\IsAdmin;

    ...

Route::middleware('auth')->group(function () {

	...

	Route::middleware(IsAdmin::class)->prefix('admin')->group(function ()
	{
		Volt::route('/dashboard', 'admin.index')->name('admin');
	});

On a besoin de quelques traductions :

"In a glance": "En un coup d'oeil",
"Dashboard": "Tableau de bord",
"Active products": "Produits actifs",
"Validated orders": "Commandes validées",
"Customers": "Clients",
"Go on store": "Aller sur la boutique",
"Successful orders": "Commandes validées",

Avec l'URL /admin/dashboard, on arrive maintenant sur le tableau de bord :

On affiche sur ce tableau de bord quelques statistiques concernant les produits, les commandes validées et les clients. Pour le moment, les liens ne mènent nulle part, nous complèterons cela lorsque nous coderons les gestions correspondantes.

On pourra ajouter plus tard d'autres informations dans le tableau de bord.

La navigation

Il faut prévoir un accès au tableau de bord à partir de la barre de navigation de la boutique (navigation.navbar) :

@if ($user = auth()->user())
    <x-dropdown>
        <x-slot:trigger>
            <x-button label="{{ $user->name }} {{ $user->firstname }}" class="btn-ghost" />
        </x-slot:trigger>
        <span class="text-black">
            @if ($user->isAdmin())
            <x-menu-item title="{{ __('Administration') }}" link="{{ route('admin') }}" />
        @endif

Et il ne faut pas oublier la barre latérale (navigation.sidebar) :

<x-menu-separator />
@if ($user->isAdmin())
    <x-menu-item title="{{ __('Administration') }}" icon="s-building-office-2" link="{{ route('admin') }}" />
@endif
<x-menu-separator />

Conclusion

La base de notre administration est désormais en place. Dans le prochain article, on complètera avec la gestion des commandes. Pour le tableau de bord, on verra plus tard avec quoi on le complète, si vous avez des idées...



Par bestmomo

Aucun commentaire

Article précédent : Shop : la commande 2/2
Article suivant : Shop : les commandes