#2 découverte FilamentPHP : création et édition

Publié le 9 février 2024 par Mathieu De Gracia
Couverture de l'article #2 découverte FilamentPHP : création et édition

Ce tutoriel est le second chapitre de notre série d'articles concernant FilamentPHP :

À la fin de notre précédent chapitre, nous avions découvert le vocabulaire du package, créé notre première ressource "User" ainsi qu'une page affichant un listing de nos utilisateurs.

Il est désormais temps d'améliorer notre ressource en y ajoutant la possibilité de créer puis d'éditer un utilisateur afin de compléter notre CRUD !

Le formulaire de création et d'édition

Retournons dans notre classe App\Filament\Resources\UserResource, créée dans le précédent chapitre, et intéressons-nous à la méthode form.

Par défaut, la méthode form d'une ressource possède la double responsabilité de gérer à la fois le formulaire de création et d'édition d'un record :

1public static function form(Form $form): Form
2{
3 return $form
4 ->schema([
5 //
6 ]);
7}

Cette méthode form fonctionnera de manière similaire à la méthode table que nous avons utilisé précédemment pour générer la liste des utilisateurs.

Quelques éléments faisant lien avec des propriétés de notre modèle User seront suffisants afin de constituer notre premier formulaire :

1public static function form(Form $form): Form
2{
3 return $form
4 ->schema([
5 Section::make()
6 ->schema([
7 TextInput::make('name'),
8 TextInput::make('email'),
9 TextInput::make('password'),
10 DatePicker::make('email_verified_at'),
11 ]),
12 ]);
13}

Bien que basique et manquant encore de quelques fonctionnalités importantes, ce formulaire est totalement fonctionnel et permettra de créer et d'éditer des utilisateurs en base de données !

N'oubliez pas d'ajouter email_verified_at dans les fillable du modèle User !

Ajoutons maintenant des restrictions, que ce soit à la création ou à l'édition, afin de s'assurer de la pertinence des informations que nous nous apprêtons à sauvegarder.

Encore une fois, la force de FilamentPHP réside dans sa grande modularité, quelques méthodes supplémentaires suffiront à enrichir vos formulaires de diverses fonctionnalités.

Pour commencer, assurons-nous de recevoir toutes les informations essentielles en rendant la saisie de plusieurs champs du formulaire obligatoires à l'aide de la méthode required :

1public static function form(Form $form): Form
2{
3 return $form
4 ->schema([
5 Section::make()
6 ->schema([
7 TextInput::make('name')
8 ->required(),
9 TextInput::make('email')
10 ->required(),
11 TextInput::make('password')
12 ->required(),
13 DatePicker::make('email_verified_at'),
14 ])
15 ]);
16}

Bien que requises, il faut désormais s'assurer que les informations transmises depuis le formulaire répondent à des contraintes plus précises pour chaque type de champ.

Dans notre situation, le nom ne doit pas dépasser une taille maximale, l'email doit être unique et respecter certaines normes, tout comme la date doit se trouver dans un intervalle précis, etc ...

1public static function form(Form $form): Form
2{
3 return $form
4 ->schema([
5 Section::make()
6 ->schema([
7 TextInput::make('name')
8 ->required()
9 ->maxLength(10),
10 TextInput::make('email')
11 ->required()
12 ->unique()
13 ->email(),
14 TextInput::make('password')
15 ->password()
16 ->revealable(),
17 DatePicker::make('email_verified_at')
18 ->maxDate(now()),
19 ])
20 ]);
21}

Pour constituer vos formulaires, FilamentPHP met à disposition une vingtaine d'inputs différents, allant du simple texte, aux checkboxes, aux selects, jusqu'au formulaire d'upload de fichiers !

Chaque élément sera également pleinement configurable, que ce soit pour modifier son apparence ou tout en partie son comportement. Vous retrouverez l'ensemble des éléments et des configurations disponibles pour créer vos formulaires à cette URL de la documentation.

Pour finir, rappelez-vous que ce formulaire est utilisé à la fois pour la création et l'édition d'un utilisateur ... cela peut s'avérer contraignant dans certains cas d'utilisation où l'ensemble des champs ne devrait pas être accessible.

Par exemple, dans le cadre d'une édition, nous ne voulons probablement pas pouvoir modifier le password ou l'adresse email d'un utilisateur.

Pour répondre à cette problématique, FilamentPHP met à disposition les méthodes disabled et visible qui permettent respectivement de désactiver ou de cacher n'importe quel élément de votre formulaire :

1public static function form(Form $form): Form
2{
3 return $form
4 ->schema([
5 Section::make()
6 ->schema([
7 TextInput::make('name')
8 ->required()
9 ->maxLength(10),
10 TextInput::make('email')
11 ->required()
12 ->email()
13 ->unique()
14 ->disabled(function (?User $record = null) {
15 return $record !== null;
16 }),
17 TextInput::make('password')
18 ->password()
19 ->revealable()
20 ->required()
21 ->visible(function (?User $record = null) {
22 return $record === null;
23 }),
24 DatePicker::make('email_verified_at')
25 ->maxDate(now()),
26 ])
27 ]);
28}

Notre formulaire est dorénavant complet, pleinement sécurisé et fonctionnel !

Le cycle de vie d’une création / édition

Que se passe-t-il dans le package quand vous validez le formulaire ?

FilamentPHP offre la possibilité de personnaliser le processus de persistance en fournissant diverses méthodes permettant d'interagir à plusieurs étapes cruciales de son cycle de vie.

En ce qui concerne la création, vous pourrez ajouter les deux méthodes suivantes dans la classe CreateUser de notre ressource :

1namespace App\Filament\Resources\UserResource\Pages;
2 
3use Illuminate\Database\Eloquent\Model;
4use App\Filament\Resources\UserResource;
5use Filament\Resources\Pages\CreateRecord;
6 
7class CreateUser extends CreateRecord
8{
9 protected static string $resource = UserResource::class;
10 
11 protected function mutateFormDataBeforeCreate(array $data): array
12 {
13 return $data;
14 }
15 
16 protected function handleRecordCreation(array $data): Model
17 {
18 return static::getModel()::create($data);
19 }
20}

Respectivement, la méthode mutateFormDataBeforeCreate manipule une variable $data contenant l'ensemble des informations validées par le formulaire avant que le record ne soit inséré en base de données.

Dans un second temps, la méthode handleRecordCreation permet de redéfinir le comportement de FilamentPHP lorsqu'il insère un nouveau record en base de données !

Vous trouverez une vue globale du cycle de vie de création d'un record dans la méthode create de la classe Filament\Resources\Pages\CreateRecord de FilamentPHP.

L'édition d'un record n'est pas en reste et des méthodes similaires existent dénommées mutateFormDataBeforeSave et handleRecordUpdate, elles devront quant à elles être insérées dans notre classe EditRecord :

1namespace App\Filament\Resources\UserResource\Pages;
2 
3use Filament\Actions;
4use Illuminate\Database\Eloquent\Model;
5use App\Filament\Resources\UserResource;
6use Filament\Resources\Pages\EditRecord;
7 
8class EditUser extends EditRecord
9{
10 protected static string $resource = UserResource::class;
11 
12 protected function getHeaderActions(): array
13 {
14 return [
15 Actions\DeleteAction::make(),
16 ];
17 }
18 
19 protected function mutateFormDataBeforeSave(array $data): array
20 {
21 return $data;
22 }
23 
24 protected function handleRecordUpdate(Model $record, array $data): Model
25 {
26 $record->update($data);
27 
28 return $record;
29 }
30}

Création multi-étapes

L'ajout d'un formulaire de création en multi-étapes, dénommée par FilamentPHP un Wizard, sera l'opportunité de dissocier le formulaire de création de celui d'édition et de décharger la méthode form de cette première responsabilité.

Grâce à ce Wizard, nous ne serons plus contraints de manipuler les méthodes "disabled" et "visible" qui pouvaient artificiellement ajouter de la complexité à notre formulaire.

Un Wizard se configure en ajoutant la méthode getSteps à notre classe CreateUser :

1 
2namespace App\Filament\Resources\UserResource\Pages;
3 
4use App\Filament\Resources\UserResource;
5use Filament\Forms\Components\Wizard\Step;
6use Filament\Resources\Pages\CreateRecord;
7 
8class CreateUser extends CreateRecord
9{
10 use CreateRecord\Concerns\HasWizard;
11 
12 protected static string $resource = UserResource::class;
13 
14 protected function getSteps(): array
15 {
16 return [
17 Step::make('Information')
18 ->schema([
19 
20 ]),
21 Step::make('Password')
22 ->schema([
23 
24 ]),
25 Step::make('Validation')
26 ->schema([
27 
28 ]),
29 ];
30 }
31}

Chaque step correspond à une étape de notre formulaire de création.

Nous pouvons désormais compléter chacune de ces étapes avec les éléments que nous avions précédemment sélectionnés pour constituer notre formulaire :

1protected function getSteps(): array
2{
3 return [
4 Step::make('Information')
5 ->schema([
6 TextInput::make('name')
7 ->required()
8 ->maxLength(10),
9 TextInput::make('email')
10 ->required()
11 ->email()
12 ->unique(),
13 ]),
14 Step::make('Password')
15 ->schema([
16 TextInput::make('password')
17 ->password()
18 ->revealable()
19 ->required(),
20 ]),
21 Step::make('Validation')
22 ->schema([
23 Toggle::make('auto_verified')
24 ->label('Validate user email')
25 ->default(false),
26 ]),
27 ];
28}

Pour finir, modifions la méthode mutateFormDataBeforeCreate afin de gérer proprement la valeur de l'élément auto_verified :

1protected function mutateFormDataBeforeCreate(array $data): array
2{
3 $data['email_verified_at'] = $data['auto_verified'] ? now() : null;
4 
5 unset($data['auto_verified']);
6 
7 return $data;
8}

Notre formulaire de création d'un utilisateur en multi étapes est maintenant fonctionnel et dissocié du formulaire d'édition !

Dans ce second tutoriel, nous avons agrémenté notre ressource d'un formulaire d'édition et de création d'un utilisateur, dans le prochain chapitre, nous aborderons les possibilités offertes par FilamentPHP pour gérer les relations !

Source : https://github.com/laravel-fr/support-filamentphp
Mathieu De Gracia avatar
Mathieu De Gracia
Des fois, mon chat code à ma place

A lire

Autres articles de la même catégorie