Il existe un certain nombre de packages pour créer une administration pour Laravel dont l'officiel Nova (qui est payant). J'ai déjà parlé dans ce blog de Voyager, Orchid, Infyom et aussi Filament dans sa première version. Mais ces articles commencent à dater un peu et il est souhaitable de rafraîchir tout ça. Je dois avouer que je me sens souvent gêné par ces outils qui sont remarquables, mais qui obligent à jongler dans les situations particulières. C'est pour cette raison que dans les exemples pratiques que je donne, je construis toujours cette partie administration pour en conserver la totale maîtrise.
Filament se présente lui-même comme un content management framework et nous promet de pouvoir construire rapidement de magnifiques interfaces d'administration. Le package bénéficie d'une sérieuse documentation. Filament est construit avec les technologies à la mode : la TALL stack. Cet acronyme résume les technologies utilisées : Tailwind, Alpine, Laravel et Livewire.
Vous pouvez télécharger le code final de cet article ici.
Cet article couvre seulement la version 3 de Filament. Si vous utilisez la version 4, reportez-vous à cet article plus récent.
Installation
Pour démarrer, on crée une nouvelle application Laravel :
composer create-project laravel/laravel filament3
On crée une base de données et on renseigne .env.
Puis, on installe Filament :
composer require filament/filament:"^3.3" -W
php artisan filament:install --panels
On se retrouve avec un nouveau provider :

Ensuite, il faut créer un compte administrateur :
php artisan make:filament-user
Là, on répond aux questions et le compte est créé. Avec l'URL .../admin/login, on arrive sur la page de connexion :

On utilise les données de l'administrateur qu'on a créé et on arrive sur le tableau de bord :

Évidemment tout est en anglais, mais il a été ajouté récemment un certain nombre de traductions dont le français, on publie les fichiers de langue :
php artisan vendor:publish --tag=filament-panels-translations

Il nous suffit maintenant de changer la locale dans la configuration (.env) :
APP_LOCALE=fr
Et c'est bon :
Les possibilités
Filament est devenu très riche en possibilités. Il n'est que de consulter la riche documentation pour le constater. Cette documentation se décompose en 8 grands chapitres :

Par rapport à la première version que j'avais analysée il y a quelques années, bien du chemin a été parcouru. Je vous propose dans cet article d'en aborder les éléments essentiels.
Des auteurs
On va créer une migration pour une table d'auteurs avec le modèle associé et le factory :
php artisan make:model Author -mfs
Dans la migration, on prévoit ce code :
public function up()
{
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->date('birth');
$table->timestamps();
});
}
On a donc :
- le nom
- la date de naissance
- les dates de création et de modification classiques
On renseigne le factory :
public function definition()
{
return [
'name' => $this->faker->name,
'birth' => $this->faker->date(),
];
}
On utilise le factory dans DatabaseSeeder pour créer 10 auteurs :
use App\Models\Author;
...
public function run()
{
Author::factory()->count(10)->create();
}
On ajoute la propriété $fillable dans le modèle Author :
protected $fillable = [
'name',
'birth',
];
Il ne reste plus qu'à lancer :
php artisan migrate --seed
On a nos 10 auteurs :

Comme on n'a pas trop pris de précautions pour les dates, il y en a de très précoces !
Une ressource pour les auteurs
Filament utilise la notion de ressource définie comme un ensemble de classes statiques qui décrivent comment un administrateur interagit avec les données de la base. On va créer une ressource pour les auteurs :
php artisan make:filament-resource Author
On a la création de plusieurs dossiers et fichiers :

La ressource proprement dite réside dans la classe AuthorResource. Cette classe permet de définir les tableaux, les formulaires, les autorisations, les pages, les autorisations, les actions....
On voit déjà le menu complété :

On va quand même changer l'icône. Filament a comme dépendance le package blade-heroicons. On a donc un peu de choix. On change dans la ressource :
public static $icon = 'heroicon-o-user';
Et ça marche :

On le préfèrerait tout de même en français, on surcharge cette propriété dans la ressource :
protected static ?string $navigationLabel = 'Auteurs';
Et maintenant, c'est mieux :

Le tableau

Pour le moment le tableau est vide :
Là aussi, j'aimerais avoir le titre en français, on peut à nouveau jouer dans la ressource :
protected static ?string $modelLabel = 'Auteur';
protected static ?string $pluralModelLabel = 'Auteurs';

Le tableau est défini dans la méthode table de la ressource :
public static function table(Table $table): Table
{
return $table
->columns([
//
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
On voit qu'on peut ajouter des colonnes, définir des filtres et des actions. Tout ça n'est pas rempli par défaut.
Concernant les colonnes, Filament propose de nombreuses possibilités :

On va se contenter d'une seule catégorie de colonne et compléter ainsi notre code :
->columns([
TextColumn::make('name')->sortable()->searchable()->label(__('Nom')),
TextColumn::make('birth')->date('d/m/Y')->sortable()->label(__('Naissance')),
])
On obtient ce tableau :

On peut trier (sortable) sur les noms et les dates de naissance et la suppression fonctionne bien.
J'ai aussi activé la recherche sur le nom en ajoutant searchable. Il apparait alors une zone de recherche :

Les formulaires

Voyons à présent comment créer les formulaires. Ça se passe dans la méthode form qui est vide au départ. On va aussi compléter le code à l'aide de la documentation :
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->label(__('Nom'))
->autofocus()
->required()
->maxLength(255)
->unique(table: Author::class),
DatePicker::make('birth')
->label(__('Naissance'))
->displayFormat('d/m/Y')
->required(),
]);
}
On ajoute directement la validation pour laquelle on dispose des principales règles de Laravel. On a ainsi un formulaire pour la modification :

Avec un joli Datepicker :

On vérifie la validation :
On va traduire ça en français en complétant le code :
TextInput::make('name')
...
->validationMessages([
'unique' => 'Le nom de l\'auteur existe déjà.',
]),
On a de la même manière un formulaire pour la création :

On a donc vu qu'avec peu de code, on a une gestion complète de notre ressource. Sans Filament, on aurait dû créer les routes, le contrôleur, les vues. Mais évidemment j'ai pris un cas très simple qui ne nous pose aucun problème particulier.
Des livres
Les auteurs sont censés écrire des livres.
On va créer une migration pour une table de livres avec le modèle et le factory associés :
php artisan make:model Book -mfs
Dans la migration, on prévoit ce code :
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->timestamps();
$table->foreignId('author_id')
->constrained()
->onDelete('cascade')
->onUpdate('cascade');
});
}
On a juste le titre pour le livre, mais surtout, on crée une clé étrangère qui lie cette table à celle des auteurs.
On ajoute la propriété $fillable dans le modèle Book :
protected $fillable = ['title'];
On ajoute la relation dans Author :
use Illuminate\Database\Eloquent\Relations\HasMany;
class Author extends Model
{
...
public function books(): HasMany
{
return $this->hasMany(Book::class);
}
}
Et la réciproque dans Book :
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Book extends Model
{
...
public function author(): BelongsTo
{
return $this->belongsTo(Author::class);
}
}
On code le factory :
public function definition()
{
return [
'title' => $this->faker->sentence(3),
];
}
On utilise le factory dans DatabaseSeeder pour créer 10 auteurs, avec pour chacun d'eux 5 livres :
public function run()
{
Author::factory()->has(Book::factory()->count(5))->count(10)->create();
}
On rafraichit les migrations et on remplit les tables (pensez à recréer l'administrateur qui va disparaitre dans l'opération) :
php artisan migrate:fresh --seed
On a de nouveau 10 auteurs, mais chacun d'eux a 5 livres.
Une ressource pour les livres
On va créer une ressource pour les livres :
php artisan make:filament-resource Book

On change l'icône dans la ressource BookResource ainsi que les traductions :
protected static ?string $navigationIcon = 'heroicon-o-book-open';
protected static ?string $navigationLabel = 'Livres';
protected static ?string $modelLabel = 'Livre';
protected static ?string $pluralModelLabel = 'Livres';
Tableau
On code le tableau :
->columns([
TextColumn::make('title')->sortable()->searchable()->label(__('Titre')),
TextColumn::make('author.name')->sortable()->label(__('Auteur')),
])

On voit qu'on a facilement ajouté le nom de l'auteur issu de la relation.
Les formulaires
On code les formulaires en tenant compte de la relation avec les auteurs :
return $form
->schema([
TextInput::make('title')
->label(__('Titre'))
->autofocus()
->required()
->maxLength(255)
->unique(table: Book::class)
->validationMessages([
'unique' => 'Le titre du livre existe déjà.',
]),
Select::make('author_id')
->label(__('Auteur'))
->relationship('author', 'name')
->searchable()
->required(),
]);

Dans le champ de l'auteur, si on clique, on a ce message qui nous propose une recherche :

On entre des caractères et on obtient la liste des auteurs qui correspondent, il suffit ensuite de cliquer sur le bon :
On s'amuse un peu
Nombre de livres par auteur
Ce qui serait intéressant, c'est d'avoir dans le tableau des auteurs le nombre de livres pour chacun. On complète la ressource AuthorResource :
->columns([
...
TextColumn::make('books_count')->counts('books')->label(__('Livres')),
])
On utilise le nom de la relation books. On doit respecter les conventions de Laravel en écrivant books_count. On dispose alors de la méthode counts pour compter les enregistrements en relation, donc ici les livres pour chaque auteur.
On obtient cet affichage :

Un bouton pour supprimer un auteur
On peut ajouter des actions dans un tableau. Voyons comment ajouter un bouton du même style que celui pour la modification, mais cette fois pour supprimer un auteur. Voici le code à prévoir :
public static function table(Table $table): Table
{
return $table
...
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('delete')
->action(fn (Author $record) => $record->delete())
->requiresConfirmation()
->modalHeading(__('Supprimer l\'auteur'))
->icon('heroicon-o-trash')
->color('danger'),
])
Quand on clique sur le bouton, on obtient cette fenêtre modale :

On peut alors annuler l'action ou supprimer effectivement l'auteur.
Conclusion
On a vu avec un exemple simple que Filament permet de construire rapidement une administration esthétique et efficace.
Par bestmomo
Aucun commentaire



