Module 8 – Architecture avancée (traits, layouts, full-page)
Niveau 5.1 – Laravel Livewire
Traits pour factoriser la logique (tri, recherche, pagination), composants full-page avec ->layout(), organisation des dossiers et nommage. En fin de module : single-use components, layouts dynamiques, conventions d’équipe.
Objectif
À la fin de ce module, vous saurez :
- Factoriser la logique commune (pagination, tri, recherche) dans des traits PHP réutilisables par plusieurs composants Livewire.
- Créer des composants full-page : un composant Livewire qui occupe toute la page en utilisant ->layout('layouts.app') (ou un layout personnalisé) et en étant invoqué depuis une route Laravel.
- Choisir entre composant embarqué (une section d’une page Blade classique) et composant full-page (tableau de bord, zone entièrement dynamique).
- Garder les composants focalisés et réutilisables pour une application maintenable.
Pourquoi structurer ?
Dès que vous avez plusieurs listes (articles, utilisateurs, commandes) avec recherche, tri et pagination, le code des propriétés et des méthodes se répète. Les traits permettent de centraliser cette logique. Par ailleurs, certaines pages sont entièrement pilotées par Livewire (tableau de bord, back-office) : les composants full-page et les layouts permettent d’avoir une page dont tout le contenu principal est un seul composant Livewire, avec un layout commun (navbar, footer).
Traits réutilisables
Un trait PHP contient des propriétés et des méthodes que vous réutilisez dans plusieurs classes. En Livewire, créez par exemple un trait WithSortingAndSearch qui définit $search, $sortField, $sortDirection et une méthode sortBy($field). Chaque composant qui a besoin de tri + recherche use WithSortingAndSearch et appelle sortBy() et orderBy($this->sortField, $this->sortDirection) dans sa requête.
Exemple de trait app/Livewire/Concerns/WithSortingAndSearch.php :
<?php
namespace App\Livewire\Concerns;
use Livewire\WithPagination;
trait WithSortingAndSearch
{
use WithPagination;
public string $search = '';
public string $sortField = 'created_at';
public string $sortDirection = 'desc';
public function updatedSearch(): void
{
$this->resetPage();
}
public function sortBy(string $field): void
{
if ($this->sortField === $field) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortField = $field;
$this->sortDirection = 'asc';
}
$this->resetPage();
}
}
Utilisation dans un composant :
<?php
namespace App\Livewire;
use App\Livewire\Concerns\WithSortingAndSearch;
use App\Models\Article;
use Livewire\Component;
class ArticleList extends Component
{
use WithSortingAndSearch;
public function render()
{
$articles = Article::query()
->when($this->search, fn ($q) => $q->where('title', 'like', '%' . $this->search . '%'))
->orderBy($this->sortField, $this->sortDirection)
->paginate(10);
return view('livewire.article-list', ['articles' => $articles]);
}
}
Le composant reste court ; la logique de tri et de recherche est partagée. Vous pouvez avoir un autre composant UserList qui use WithSortingAndSearch et adapte uniquement le modèle et les colonnes.
Composants full-page
Par défaut, un composant Livewire est inclus dans une page Blade (ex. <livewire:article-list /> dans welcome.blade.php). Parfois vous voulez qu’une route Laravel affiche directement un composant Livewire comme contenu principal de la page (sans wrapper Blade autour). On parle de full-page component.
Étapes :
- Créer le composant (ex. Dashboard).
- Dans render(), retourner la vue avec un layout :
return view('livewire.dashboard')->layout('layouts.app');. Le layout reçoit le contenu du composant dans la variable $slot (ou selon la structure de votre layout). - Définir une route qui renvoie la vue du composant. En Livewire 3, on peut utiliser Route::get('/dashboard', Dashboard::class) (si le composant est un single-use component full-page). Ou une route qui rend une vue Blade qui contient uniquement
<livewire:dashboard />avec le layout.
Exemple de composant full-page :
<?php
namespace App\Livewire;
use Livewire\Component;
class Dashboard extends Component
{
public function render()
{
return view('livewire.dashboard')
->layout('layouts.app');
}
}
Vue resources/views/livewire/dashboard.blade.php : le HTML du tableau de bord (widgets, listes, etc.). Le layout layouts.app doit définir un endroit pour le contenu (ex. {{ $slot }}).
Route (option simple : vue Blade qui inclut le composant avec le même layout) :
Route::get('/dashboard', function () {
return view('dashboard'); // dashboard.blade.php contient <livewire:dashboard />
});
Ou, avec Livewire 3, vous pouvez exposer le composant comme page via un single-use full-page (voir la doc Livewire pour Route::get('/dashboard', Dashboard::class) selon votre version). L’idée reste : une URL = un composant Livewire qui rend une vue avec ->layout().
Layouts personnalisés
Le layout passé à ->layout('layouts.app') est une vue Blade classique. Vous pouvez en avoir plusieurs : layouts.app (navbar + footer), layouts.admin (sidebar admin), etc. Le layout reçoit généralement $slot pour le contenu principal et peut recevoir des données si vous utilisez ->layout('layouts.app', ['title' => 'Dashboard']).
Exemple :
return view('livewire.dashboard')
->layout('layouts.app', [
'title' => 'Tableau de bord',
]);
Dans layouts.app, utilisez $title dans le <title> ou un en-tête.
Bonnes pratiques
- Un composant = une responsabilité : par exemple une liste d’articles, un formulaire de contact. Évitez les composants monolithiques qui font liste + formulaire + modale + tout.
- Traits pour la logique commune (tri, recherche, pagination) ; composants pour la logique spécifique (quel modèle, quelles colonnes, quelle vue).
- Full-page pour les pages entièrement dynamiques (dashboard, back-office). Composant embarqué pour une section réactive dans une page sinon (ex. un bloc « Derniers articles » avec filtre).
- Nommage : préfixer les traits par With (ex. WithSortingAndSearch), ranger les traits dans un sous-dossier Concerns ou Traits pour la clarté.
À retenir
- Traits : factoriser pagination, tri, recherche dans un trait (ex. WithSortingAndSearch) et l’utiliser dans plusieurs composants pour éviter la duplication.
- Full-page : un composant qui rend toute la page avec return view('livewire.xxx')->layout('layouts.app'). Idéal pour tableaux de bord ou sections 100 % Livewire.
- Layouts : vues Blade classiques (navbar, footer) ; le contenu du composant est injecté via $slot. Vous pouvez passer des données au layout en second argument de layout().
- Garder les composants focalisés et réutilisables pour une base de code maintenable.
Approfondissement
- Single-use (full-page) et route : en Livewire 3 vous pouvez enregistrer une route qui rend directement un composant full-page :
Route::get('/dashboard', Dashboard::class). Le composant doit retourner une vue avec ->layout(). Ainsi plus besoin d’une vue Blade intermédiaire qui contient<livewire:dashboard />. - Layout dynamique : vous pouvez choisir le layout selon le contexte :
return view('livewire.admin.dashboard')->layout($this->user->isAdmin() ? 'layouts.admin' : 'layouts.app');. Utile pour des zones admin vs utilisateur avec des sidebars différentes. - Conventions d’équipe : ranger les traits dans App\Livewire\Concerns ou App\Livewire\Traits ; préfixer par With (WithSortingAndSearch). Pour les full-page, un sous-dossier App\Livewire\Pages et des vues dans livewire/pages/ garde la séparation entre « composants réutilisables » et « pages ».
À retenir
- Traits pour partager tri, recherche, pagination ; full-page avec ->layout('layouts.app') pour des pages 100 % Livewire ; wire:target et composants focalisés pour la maintenabilité.
Dans le prochain module, nous abordons la sécurité et les permissions : validation côté serveur, autorisation (policies), et protection contre les abus (rate limiting, CSRF déjà géré par Livewire).