Drupal 9 vous propose la classe confirmFormBase qui étends FormBase. Cela permet de rapidement rajouter une étape à un formulaire pour valider une action. L'utilisation courante est de confirmer la suppression de quelque chose, cela permet d'informer : "êtes-vous sûr de vouloir supprimer le noeud 23 ?"
L'utilisation standard est de créer une route avec un paramètre (par exemple un id) et donc d'avoir votre formulaire qui étends formBase et un second formulaire pour confirmer l'action qui étends confirmFormBase.
Un seul formulaire avec notre étape de confirmation
Mais dans notre cas nous voulons créer un seul formulaire et utiliser la confirmation au sein de ce formulaire. Cette solution existe déjà dans Drupal core et est utilisé pour l'import d'une configuration simple, la classe ConfigSingleImportForm.php.
L'astuce est alors d'implémenter dans notre classe qui étends confirmFormBase les méthodes de formBase, soit depuis formInterface :
public function getFormId();
public function buildForm(array $form, FormStateInterface $form_state);
public function submitForm(array &$form, FormStateInterface $form_state);
// Si besoin d'une validation.
public function validateForm(array &$form, FormStateInterface $form_state);
Et depuis confirmFormInterface
public function getQuestion();
public function getCancelUrl();
Ensuite la première étape est d'ajouter une variable pour stocker la data de notre formulaire que l'on veut stocker. Cela peut être un
protected $action = NULL;
Le plus important est alors d'ajouter une condition au submitForm()
pour ne pas encore soumettre, reconstruire le formulaire et stocker notre action dans une variable de notre classe :
public function submitForm(array &$form, FormStateInterface $form_state): void {
if (!$this->action) {
$form_state->setRebuild();
$this->action = $form_state->getValue('action');
return;
}
// Notre code submit.
}
Il suffit ensuite simplement d'avoir une condition également au buildForm()
pour ne pas utiliser notre formulaire mais renvoyer celui de confirmation présent dans confirmFormBase :
public function buildForm(array $form, FormStateInterface $form_state): array {
if ($this->action) {
return parent::buildForm($form, $form_state);
}
// Notre array $form avec les boutons d'action, au minimum "soumettre"
}
De même, si le formulaire contient une validation avec validateForm()
il est nécessaire d'éviter la validation lors de l'étape de confirmation :
public function validateForm(array &$form, FormStateInterface $form_state): void {
if ($this->action) {
return;
}
// Notre code de validation.
}
Exemple complet de code
Voici un exemple complet d'implémentation pour n'avoir qu'un seul formulaire au lieu de deux et qui permet également de traiter des données plus complexes qu'un id.
demo_confirm_form.routing.yml
Voici un exemple minimum de formulaire web/modules/demo_confirm_form/src/Form/ExampleMinimalForm.php
Un exemple plus complet de formaulaire avec un texte et un array, web/modules/demo_confirm_form/src/Form/ExampleForm.php