Ce tutoriel est le second chapitre de notre série d'articles concernant FilamentPHP :
- #1 Installation & listing
- #2 Création et édition
- #3 Les relations
À 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): Form2{3 return $form4 ->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(): array13 {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): array2{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
A lire
Autres articles de la même catégorie
Les failles RCE dans Laravel
Une faille RCE consiste à injecter puis exécuter arbitrairement du code dans une application, voyons comment exploiter l’une d’entre elles dans un Laravel 9 !
Mathieu De Gracia
Des DTO sans laravel-data
Et si vous n'aviez pas besoin de laravel-data pour vos DTO ?
Mathieu De Gracia
#3 découverte FilamentPHP : les relations
Troisième article de cette série de tutoriels : intéressons-nous aux relations !
Mathieu De Gracia