Bonjour à tous,

Tout est dans le titre : je voudrais pouvoir vérifier qu'un premier formulaire soit valide avant de faire appel à un autre, or, apparament on ne peut pas réutiliser les méthodes d'un controller dans un autre ???

Dans mon cas j'essaie de récupérer le boolean isValid de mon formulaire 1 (creerFacture()) avant d'ouvrir celui de la création de lignes de factures (creerLigne()) qui est indépendant / non imbriqué...

Faut il obligatoirement passer par un service ?

D'autre part, j'aurais besoin que la variable 'numdocument' soit directement injectée dans le form 2.

Merci pour votre aide.

//Créer une facture
    #[Route('/creer-facture', name: 'creer-facture')]
    public function creerFacture(EcrituresRepository $ecrituresRepository, EntityManagerInterface $em, Request $request): Response
    {
        $titre = "Créer une facture";
        $ecriture = (new Ecritures());
        $numdocument = $ecrituresRepository->getNouveauNumeroFacture();

        $ecriture
            ->setNumDocument($numdocument)
            ->setDateDocument(new \DateTimeImmutable())
            ->setTypeDocument('Facture')
            ->setEtatDocument('En création');

        $formEcritures = $this->createForm(EcrituresType::class, $ecriture);
        $formEcritures->handleRequest($request);

        if ($formEcritures->isSubmitted() && $formEcritures->isValid()) {
            $em->persist($ecriture);
            $em->flush();

            $this->addFlash('success', 'La nouvelle facture a été enregistrée avec succès dans la base.');
        }

        return $this->render('ecritures/ecritures-form.html.twig', [
            'formEcritures' => $formEcritures->createView(),
            'titre' => $titre
        ]);
    }

    //Creer des ligne de factures
    #[Route('/creer-lignes-facture',name:'creer-lignes-facture')]
    public function creerLigne(EntityManagerInterface $em,Request $request):Response{

        //Vérification données du formulaire écritures avant ajout de ligne de détails
        if ($this->formEcritures->isValid()) {
            $ligne = new DetailsEcritures();
                $ligne
                ->setNumDocument($this->$numdocument);

                $formCreerLignes=$this->createForm(DetailsEcrituresType::class,$ligne);
                $formCreerLignes->handleRequest($request);

                if($formCreerLignes->isSubmitted()&& $formCreerLignes->isValid()){
                    $em->persist($ligne);
                    $em->flush();
                }
                    return $this->render('ecritures/details-ecritures-form.html.twig',[
                        'formCreerLignes'=>$formCreerLignes->createView()
                    ]);
            ;
        } else {
            return new Exception("Veuillez au préalable remplir tous les champs obligatoires...");
        }
    }

9 réponses


Hello,

Sans forcément connaître la technologie que tu utilises, tu devrais découper (comme tu sembles l'avoir fait) en plusieurs étapes :

La première : Formulaire de création de facture qui renvoi la vue (et donc le formulaire).
La seconde : Une fonction (et donc une URL) qui gère la soumission du formulaire (validation, enregistrement des données, etc).
La troisième : Si le formulaire est validé et les données enregistrées, tu peux rediriger l'utilisateur vers une nouvelle url, exemple : /factures/XXX/creer-line où XXX est l'identifiant de la facture précédemment créée.

Ta fonction "creerLigne" prendra donc un paramètre dans l'URL qui sera l'identifiant de la facture qui retournera le dit formulaire de création de ligne pour le formulaire créé.

J'espère avoir été clair en tout cas, sinon n'hésite pas.

Edit :

Tu aurais donc 4 fonctions, 4 URLs :

  • GET /creer-facture -> Cette URL fera appel à une méthode qui rendra la vue du formulaire
  • POST /creer-facture -> Cette URL et fonction traitera les informations du formulaire pour les entregistrer, et redirigera vers /factures/XXX/creer-ligne si valide.
  • GET /factures/XXX/creer-ligne -> Cette URL fera appel à une méthode qui rendra la vue du formulaire en lui envoyant XXX de l'URL (à toi d'effectuer les vérifications nécessaires)
  • POST /factures/XXX/creer-ligne -> Cette URL et fonction traitera les informations du formulaire.

Bonjour et merci Azorgh pour cette réponse bien fournie, cependant, je ne peux l'appliquer dans ce cas précis, je m'explique :

1/ Dans un second temps la fonction 'creeLigne' sera déclenchée au click d'un bouton et ouvrira donc à chaque fois le formulaire n° 2 (Je l'ai déjà mise en place entre temps pour tester...), le click sur le dit bouton devra déclencher aussi et en premier lieu un check sur la validité du formulaire n°1 à chaque fois + d'autres contrôles à venir, or , c'est justement là qu'il y a problème, je ne sais pas récupérer l'état de validation du premier formulaire dans la fonction creerLigne même en faisant qqe chose du genre $this->creerFacture->$formEcritures->isValid()...

Je ne peux faire de return dans la fonction creerFacture() indiquant si le formulaire est valide ou pas... en plus d'être un non sens puisque l'on devrait pouvoir capter si le formulaire isvalid() ou pas même à distance dans le reste du code non ?

Comment fait on lorsque l'on découpe une validation en plusieurs séquences/ étapes et sur plusieurs formulaires ? Je me pose la question !

De ce que j'ai compris en recherchant en plusieurs langues sur internet c'est qu'il faudrait obligatoriement passer par un 'service' pour pouvoir échanger les variables et objets entre plusieurs formulaires, j'aurais donc besoin d'une confirmation dans ce sens...

2/D'un autre coté il ne faut surtout pas que le numéro de facture apparaisse en GET dans l'url par mesure de sécurité et pour éviter qu'un utilisateur puisse modifier une facture en passant simplement un numéro ou référence dans la barre d'adresse.

Bonjour,

Une intéraction dans une formulaire nécessite du javascript.
Il faudrait stopper l'évenèement afficher le nouveau formulaire.

Sinon tu crée deux controller différent. Au clique du formulaire, tu fais une redirection sur un nouveau controller qui attend un post avec les deux formulaires correspondants.

Pour imbriquer deux formulaires différents. Il faut créer deux form type. Ton form principal appel ton form secondaire via un type collection.

Bonjour Jessy brs

Alors ... il s'agît bien de deux formulaires indépendants... Le fait de faire deux controllers ne répondra pas sauf erreur de ma part à ma nécessité première : comment vérifier la validité du form 1 avant de pouvoir ouvrir le form 2 (le form 2 servant à ajouter des lignes de facture ) grâce à un bouton ?

Pour l'instant j'ai mis en place le bouton qui dirige vers une autre route et ouvre le formulaire mais cela est fait sans contrôle de validité du form 1 ce qui ne peut rester en l'état... Je pensais pouvoir récupérer l'état du form 1 dans la fonction creerLigne() mais apparament c'est impossible...

L'interêt étant d'ajouter des lignes de facture que si le formulaire 1 est complet, car l'on peut avoir besoin de modifier ou rajouter des lignes plus tard avant encaissement et fermeture définitive du document...

Il doit bien y avoir une astuce et sans passer par un tableau de session ...

Bonjour Jean.

Le controller est là pour gérer ta logique.
Ensuite, dès que tu commences à mettre en place une logique dans ton controller. Exemple "creerLigne()". Oui le top est de le mettre dans un service. (une classe).
Ton controller va donc appeler ton service qui contient la method. On respect le principe, une method, une seule action.

Sinon, nous ne connaissons pas tes entités. Un peu difficile pour te guider. En revanche les solutions pour ton problèmes sont les suivantes.

Ta class "Ecritures" doit avoir une propriété OneToMany vers ta class DetailsEcritures. exemples "detailsEcritures. ( au passage tes entités ne doivent pas être au pluriels, attention au nommage. Il faut être explicite)

Ensuite tu vas créer deux formType.
form/EcrituresFormType qui va permettre d'enregistrer ta facture (ton entité)
form/DetailsEcritures qui va enregistrer ton entité. J'imagine qu'il n'y aura qu'un seul élément (propriété) de type string ou autre.

Ensuite dans ton formType tu vas ajouter une propriété "DetailsEcritures" qui sera de type "CollectionType" et qui va pointer vers le formulaire DetailsEcritures.

Ainsi depuis ton formulaire EcrituresFormType tu vas pouvoir ajouter ou supprimer auttant de lignes que tu souhaites de ton entité "DetailsEcritures"

Bonjour Jessy,

Bon, concernant la mécanique ecriture/lignes ecritures elle est déjà en place et marche déjà parfaitement ..., là n'était pas ma question :

Je dois maintenant mettre en place une vérification concernant le form 1 à l'appui sur le bouton permettant d'ouvrir le form 2 et si form 1 valide alors passer au form 2 la variable "numdocument", si form 1 non valide alors message utilisateur (pour éviter l'ajout de lignes).

Cela paraît simple mais non, car ni l'état du form 1 ni la variable numdocument ne semblent être disponibles dans le deuxième controller / fonction (creerLigne())...

Je pensais pouvoir interroger depuis le form 2 le isValid() du form 1 mais impossible, sauf erreur de ma part...

ma réponse reste inchangé.
le plus simple dans ton cas semble utiliser deux controller différent.

a la soumissions du premier. tu valides le formulaire. Redirection post sur le second controller en récupérant le premier formulaire qui sera du coup pre rempli.
tu le récupères avec l'id de l'objet créer.

sinon tu peux le faire en JavaScript si tu souhaites faire une vérification sans rafraîchir la page.

dans tous les cas tu vas devoir utiliser le collectionType.

Merci Jessy,

Je vais tenter votre approche avec deux controllers...

A quel collectionType faites vous reference ?

premier contrôler.
tu as t'on formulaire référence à votr facture.
à la soumission du formulaire.
vous enregistrer l'entité et faite une redirection vers le second controller en récupérant l'id de votre entité.

ce qui donne
facture/new -> soumission du formulaire -> facture/47

Dans le second controller vous récupérez donc votre facture soumis auparavant grâce à l'id dans l'URL. symfony le fair automatiquement avec le param converter. ne pas oublier de le mettre l'entité de la facture dans l'argument du controller.

et ensuite vous ajoutez dans le formulaire de votre facture un type collectionType qui va pointer vers le formType de votre second entité pour créer une ligne.

cela permet de créer autant de ligne souhaitez associé à une facture.

voila les grosses lignes et bon courage