Bonjour, je suis un débutant en symfony, j'essaie de hoster des informations grâce à un formulaire qui fonctionne comme ceci:

  • On copie/colle une URL youtube dans une input
  • On confirme avec un bouton
  • L'API Youtube va chercher les informations dont j'ai besoin
  • Les informations s'affichent, l'input précédent disparait et on peut choisir les tags appropriés pour cette vidéo
  • On confirme avec un bouton

Je ne sais pas vraiment ou me diriger, j'ai essayé quelques solutions et j'ai réussi à en faire fonctionner une mais qui était un peu "sale" (form dans un form), et qui avait un bug d'affichage (l'input précédent se mettait en fin de page).

J'essaye donc de le faire proprement mais je ne sais pas trop comment m'y prendre.

Pour l'instant j'ai ça :

    #[Route('/new', name: 'app_videos_new', methods: ['GET', 'POST'])]
    public function new(Request $request, EntityManagerInterface $entityManager): Response
    {
        $displayInfos = false;
        $errorBool = false;
        $errorMsg = '';
        $videoInfos = null;
        $video = new Videos();

        $form = $this->createForm(VideoIDType::class, $video);
        $form2 = $this->createForm(VideoTagsType::class, $video);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $url = $form->get('video_id')->getData();
            $videoID = $this->getYoutubeIdFromUrl($url);

            if (isset($videoID) != false) {
                $displayInfos = true;
                $videoInfos = $this->getYoutubeInfos($videoID);
                $this->setYoutubeInfos($video, $videoInfos);

                $entityManager->persist($video);
                $entityManager->flush();
            } else {
                //Handle if return false
                $errorBool = true;
                $errorMsg = 'Le lien de la vidéo n\'est pas valide';
                return $this->redirectToRoute('app_videos_new', [], Response::HTTP_SEE_OTHER);
            }
        } else {
            // Handle fail form submit
        }

        $form2->handleRequest($request);

        if ($form2->isSubmitted() && $form2->isValid()) {
            $datas = $form2->get('tags')->getData();

            for ($i = 0; $i < count($datas); $i++) {
                $video->addTag($datas[$i]);
            }

            $entityManager->flush();

            return $this->redirectToRoute('app_videos_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->render('videos/new.html.twig', [
            'displayInfos' => $displayInfos,
            'errorBool' => $errorBool,
            'errorMsg' => $errorMsg,
            'videoInfos' => $videoInfos,
            'video' => $video,
            'form' => $form->createView(),
            'form2' => $form2->createView(),
        ]);
    }

Cette version ne me permet pas de garder les infos que j'ai traité dans le form1, dans le form2.
J'avais aussi une version ou le "if ($form2->isSubmitted() && $form2->isValid())" était dans le
: "if ($form->isSubmitted() && $form->isValid())" mais le problème c'était que les inputs des tags n'était pas pris en compte.

Merci d'avance de votre aide, J'ai d'autres infos si vous avez besoin, j'ai limité pour ne pas surcharger le post.

3 réponses


Bonjour,

Il y a plusieurs approches possibles. Voici une première approche:

  • Utiliser des cessions pour stocker de manière temporaire les données entres les étapes du formulaire.
[Route('/new', name: 'app_videos_new', methods: ['GET', 'POST'])]

public function new(Request $request, EntityManagerInterface $entityManager, SessionInterface $session): Response
{
$video = new Videos();
$form = $this->createForm(VideoIDType::class, $video);
$form2 = $this->createForm(VideoTagsType::class, $video);

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    $url = $form->get('video_id')->getData();
    $videoID = $this->getYoutubeIdFromUrl($url);

    if (isset($videoID)) {
        $videoInfos = $this->getYoutubeInfos($videoID);
        $this->setYoutubeInfos($video, $videoInfos);

        // Stockez les informations dans la session
        $session->set('videoInfos', $videoInfos);

        $entityManager->persist($video);
        $entityManager->flush();

        return $this->redirectToRoute('app_videos_new', [], Response::HTTP_SEE_OTHER);
    } else {
        // Gérez le cas où l'ID de la vidéo n'est pas valide
    }
}

$form2->handleRequest($request);

if ($form2->isSubmitted() && $form2->isValid()) {
    // Récupérez les informations stockées dans la session
    $videoInfos = $session->get('videoInfos');

    $datas = $form2->get('tags')->getData();

    for ($i = 0; $i < count($datas); $i++) {
        $video->addTag($datas[$i]);
    }

    $entityManager->flush();

    // Nettoyez les informations de la session
    $session->remove('videoInfos');

    return $this->redirectToRoute('app_videos_index', [], Response::HTTP_SEE_OTHER);
}

return $this->render('videos/new.html.twig', [
    'video' => $video,
    'form' => $form->createView(),
    'form2' => $form2->createView(),
]);

}

Assurez-vous d'ajouter use Symfony\Component\HttpFoundation\Session\SessionInterface; au début de votre fichier pour utiliser la session.

A part ça, vous pouvez:

  • Optez pour une approche consolidée en regroupant les deux formulaires sous une seule action. Cette méthode, recommandée pour l'affichage et le traitement de la soumission, vous permet de fusionner les deux formulaires dans une seule action et d'utiliser des conditions pour identifier le formulaire soumis.

  • Optez aussi pour des noms de formulaires uniques : Veillez à ce que chaque formulaire ait un nom distinct. En ajustant le deuxième argument de la méthode createForm dans votre code, attribuez des noms différents à chaque formulaire.

  • Appliquez handleRequest à chaque formulaire : Assurez-vous d'appeler la méthode handleRequest pour chaque formulaire au sein de votre boucle foreach. Cela garantira un traitement adéquat de chaque soumission de formulaire.

  • Utilisez des variables distinctes pour chaque formulaire dans votre template Twig : Pour afficher les formulaires de manière distincte, créez des variables spécifiques pour chacun d'eux dans votre template. Employez la méthode createView pour chaque formulaire et transmettez-les individuellement à votre template.

Ex:
public function edition(Request $request, Category $content): Response
{
$editCategoryForm = $this->createForm(EditCategoryType::class, $content);
$createPostForm = $this->createForm(CreatePostType::class);

$editCategoryForm->handleRequest($request);
$createPostForm->handleRequest($request);

if ($editCategoryForm->isSubmitted() && $editCategoryForm->isValid()) {
    // Traitement du formulaire d'édition de catégorie
}

if ($createPostForm->isSubmitted() && $createPostForm->isValid()) {
    // Traitement du formulaire de création de post
}

return $this->render(
    'content/edition.html.twig',
    [
        'editCategoryForm' => $editCategoryForm->createView(),
        'createPostForm' => $createPostForm->createView(),
        'content' => $content,
    ]
);

}

Dans votre template Twig, vous pouvez ensuite afficher les formulaires séparément

{{ form_start(editCategoryForm) }}
{{ form_errors(editCategoryForm) }}
{{ form_widget(editCategoryForm) }}
<button type="submit">Valider</button>
{{ form_end(editCategoryForm) }}

{{ form_start(createPostForm) }}
{{ form_errors(createPostForm) }}
{{ form_widget(createPostForm) }}
<button type="submit">Valider</button>
{{ form_end(createPostForm) }}

Jakdax
Auteur

Merci beaucoup de votre réponse, comme j'ai besoin d'avancer rapidement (j'ai une présentation sur ce projet le jeudi qui arrive). Je suis parti sur la solution de facilité et de le gérer avec 2 routes différentes, ce qui fonctionne parfaitement.

Cependant quand j'aurais le temps d'optimiser l'expérience utilisateur, je vais essayer votre solution.

Merci beaucoup de votre aide Mimiclcl !