Partage
  • Partager sur Facebook
  • Partager sur Twitter

Symfony 5, Pagination par id

    29 novembre 2021 à 11:02:58

    Bonjour, je suis actuellement en alternance et j'ai un projet symfony qui consiste à créer une enquête de satisfaction, après plusieurs heures/jours de recherches je bloque sur un aspect très important qui est la pagination, j'aimerai si cela est possible paginer mon enquète par catégorie, cela signifie, que pour chaque catégorie de questions je les affiches puis lorsque que l'on change de page on arrive sur la deuxieme catégorie et ses questions etc etc, j'utilise KnpPaginator de manière général. Voici mon code avec des essaies peu concluant. Si quelqu'un avait une piste ou un exmple à me proposer je suis preneur. Merci à vous 

     twig : 

    {% extends 'base.html.twig' %}
    
    {% block title %}Hello TestControllerBisController!{% endblock %}
    
    {% block body %}
    <style>
        body {
            background-image: url("https://images.pexels.com/photos/1367192/pexels-photo-1367192.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") !important;
        }
    </style>
    
    <div class="container emailUser" style="width: 75%">
        <div class="container" style="text-align: center;">
            <h2>Votre avis est important pour CFBL</h2>
        </div>
        <div style="border-bottom: 1px solid rgb(0, 118, 51); font-size : 13pt">
            <p>La satisfaction des adhérents est la priorité de CFBL.</p>
            <p>En répondant à ce questionnaire, vous aidez CFBL à améliorer la qualité de ses prestations futures.</p>
            <p>Merci de nous valider les informations suivantes :</p>
        </div>
        <div style="padding-top: 15px">
            {% if app.user %}
                <div class="noPartage">
                    <svg id="noVisionCompte" xmlns="http://www.w3.org/2000/svg" width="25" height="25"
                         fill="currentColor"
                         class="bi bi-eye-slash" viewBox="0 0 16 16">
                        <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944
                             5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83
                              1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/>
                        <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943
                             1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
                        <path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465
                             1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0
                             8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/>
                    </svg> {{ app.user.login }} (non partagé)
                </div>
                <a style="padding : 0; padding-left: 15px" class="nav-link active"
                   href="{{ path('app_logout') }}"><small>Changer de
                        compte</small></a>
            {% endif %}
    
            <p style="color : red">* Champ obligatoire</p>
        </div>
    </div>
    
    <div class="container tableauQuestions table-responsive" style="width: 75%">
        <table class="table">
            <thead>
            <tr>
                <th class="thCategorie">
                    {% for categories in categorie1 %}
                        {{ categories.libelle }} :
                    {% endfor %}
    
                    {# {% for questions in question1 %} #}
                    {# <li>{{ questions.question }}</li> #}
                    {# {% endfor %} #}
                </th>
            </tr>
            </thead>
            {{ form_start(formFormulaire, {attr: {'novalidate': 'novalidate'}}) }}
            <tbody class="table-hover">
            {% for reponse in formFormulaire.reponses %}
                <tr>
                    <td>
                        {# TODO : ne pas afficher la catégorie si la même que la réponse précédente #}
                        {# <div>{{ reponse.vars.data.question.categories.libelle }}</div> #}
                        <div>{{ reponse.vars.data.question.question }}<span style="color: red"> *</span></div>
                        <br>
                        <div>{{ form_row(reponse.choice) }}</div>
                        <br>
                        <div>{{ form_row(reponse.commentaire) }}</div>
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
        <button type="submit" class="btn btn-success">Valider</button>
        {{ form_end(formFormulaire) }}
    </div>
    
    {# <div> #}
        {# {%  if listAllQuestions.categorie.id == 2 %} #}
        {# {{ reponse.vars.data.question.question }} #}
        {# {% endif %} #}
        {# </div> #}
    
    
    <div class="container">
        <table>
            <thead>
            <tr>
                {% for categories in categorie1 %}
                    {{ categories.libelle }} :
                {% endfor %}
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>
                    {% for questions in question1 %}
                        {{ questions.question }}
                    {% endfor %}
                </td>
            </tr>
            </tbody>
        </table>
    </div>
    
    {% endblock %}
    

    Controller :

    <?php
    
    namespace App\Controller;
    
    
    use App\Entity\Categories;
    use App\Entity\Formulaire;
    use App\Entity\Questions;
    use App\Entity\Reponse;
    use App\Form\FormulaireFormType;
    use App\Repository\CategoriesRepository;
    use App\Repository\QuestionsRepository;
    
    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    
    class TestControllerBisController extends AbstractController
    {
        /**
         * @Route("/test/controller/bis", name="test_controller_bis")
         */
        public function test(Request $request, QuestionsRepository $questionsRepository, EntityManagerInterface $entityManager,
        CategoriesRepository $categoriesRepository): Response
        {
            
    
            // création d'un nouveau formulaire
            $formulaire = new Formulaire();
            // on associe l'utilisateur connecté au formulaire
            $formulaire->setUtilisateur($this->getUser());
            // recherche de la liste de toutes les questions
            $questions = $questionsRepository->findAll();
            // on insère les questions dans le nouveau formulaire
            foreach ($questions as $question) {
                $reponse = new Reponse();
                $reponse->setFormulaire($formulaire);
                $reponse->setQuestion($question);
                $formulaire->addReponse($reponse);
            }
    
            $question1 = $this->getDoctrine()->getRepository(Questions::class)->findBy(
              array('categories'=>'1')
            );
            
            $categorie1 = $this->getDoctrine()->getRepository(Categories::class)->
            findBy(
                array('libelle'=> 'Vos chantiers'),
            );
            $categorie2 = $this->getDoctrine()->getRepository(Categories::class)->
            findBy(
                array('libelle'=> 'Relations commerciales'),
            );
    
    
            // création du formulaire
            $formFormulaire = $this->createForm(FormulaireFormType::class, $formulaire);
            $formFormulaire->handleRequest($request);
            if ($formFormulaire->isSubmitted() && $formFormulaire->isValid()) {
                // traitement de sauvegarde du formulaire
                $entityManager->persist($formulaire);
                $entityManager->flush();
    
    
    
            }
            return $this->render('test_controller_bis/index.html.twig', [
                'formFormulaire' => $formFormulaire->createView(),
                'categorie1' => $categorie1,
                'categorie2' => $categorie2,
                'question1' => $question1,
            ]);
        }
    }
    




    • Partager sur Facebook
    • Partager sur Twitter
      29 novembre 2021 à 11:50:38

      Salut

      Il faut bien se rendre compte que si on parle de pagination dans ce que tu expliques, ce sont les catégories qui sont paginées une à une, et non les questions elles-mêmes. Si cependant tu dois n'afficher qu'une question à la fois, c'est très légèrement différent, en cela qu'on va paginer les questions a minima ordonnées par catégories pour que celles-ci se suivent.

      • Partager sur Facebook
      • Partager sur Twitter
        29 novembre 2021 à 12:59:21

        Et bien pour faire clair j'ai 8 catégories qui contiennent entre 2 et 3 questions, je doit afficher, sur chaque page, la catégorie et les questions liées. Donc si j'ai bien compris je doit baser mon système sur les catégories, mais je n'ai pas la moindre idée de comment m'y prendre... j'arrive à afficher une catégorie et les questions liées à celle-ci mais ducoup ma collection de form ne fonctionne plus et une erreur survient.
        • Partager sur Facebook
        • Partager sur Twitter
          29 novembre 2021 à 15:37:37

          Et si tu nous disais quelle(s) erreur(s), histoire qu'on perde moins de temps en suppositions et en devinettes ?

          Probablement qu'il nous faudra le code de FormulaireFormType.

          -
          Edité par Ymox 29 novembre 2021 à 15:37:54

          • Partager sur Facebook
          • Partager sur Twitter
            29 novembre 2021 à 15:42:16

            Erreur : 

            An exception has been thrown during the rendering of a template ("Field "choice" has already been rendered, save the result of previous render call to a variable and output that instead.").

            FormulaireFormType : 

            class FormulaireFormType extends AbstractType
            {
                public function buildForm(FormBuilderInterface $builder, array $options): void
                {
                    $builder
                        ->add('reponses', CollectionType::class, [
                            'entry_type' => ReponseFormType::class,
                            'entry_options' => ['label' => false],
                        ]);
                }
            
                public function configureOptions(OptionsResolver $resolver): void
                {
                    $resolver->setDefaults([
                        'data_class' => Formulaire::class,
                    ]);
                }
            }

            ReponseFormType : 

            class ReponseFormType extends AbstractType
            {
                public function buildForm(FormBuilderInterface $builder, array $options): void
                {
                    $builder
            //            ->add('Questions', EntityType::class, [
            //                'class' => Questions::class,
            //                'choice_label' => 'question',
            //                'attr' => [
            //                    'class' => 'form-select'
            //                ]
            //            ])
            
                        ->add('choice', EntityType::class, [
                            'class' => Choix::class,
                            'label' => false,
                            'choice_label' => 'label',
                            'multiple' => false,
                            'expanded' => true,
                            'attr' => [
                                'class' => 'radio_button',
                            ]
                        ])
            
                        ->add('commentaire', TextareaType::class, [
                            'label' => 'Si peu ou pas satisfait, merci de préciser',
                            'required'=>false,
                            'attr' => [
                                'placeholder' => 'Votre réponse ...',
                                'class' => 'form-control'
                            ]
                        ]);
                }
            
                public function configureOptions(OptionsResolver $resolver): void
                {
                    $resolver->setDefaults([
                        'data_class' => Reponse::class,
                    ]);
                }
            }
            




            • Partager sur Facebook
            • Partager sur Twitter
              29 novembre 2021 à 15:44:06

              OK, et la vue test_controller_bis/index.html.twig s'il te plaît.

              • Partager sur Facebook
              • Partager sur Twitter
                29 novembre 2021 à 15:48:04

                {% extends 'base.html.twig' %}
                
                {% block title %}Hello TestControllerBisController!{% endblock %}
                
                {% block body %}
                    <style>
                        body {
                            background-image: url("https://images.pexels.com/photos/1367192/pexels-photo-1367192.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260") !important;
                        }
                    </style>
                
                    <div class="container emailUser" style="width: 75%">
                        <div class="container" style="text-align: center;">
                            <h2>Votre avis est important pour CFBL</h2>
                        </div>
                        <div style="border-bottom: 1px solid rgb(0, 118, 51); font-size : 13pt">
                            <p>La satisfaction des adhérents est la priorité de CFBL.</p>
                            <p>En répondant à ce questionnaire, vous aidez CFBL à améliorer la qualité de ses prestations futures.</p>
                            <p>Merci de nous valider les informations suivantes :</p>
                        </div>
                        <div style="padding-top: 15px">
                            {% if app.user %}
                                <div class="noPartage">
                                    <svg id="noVisionCompte" xmlns="http://www.w3.org/2000/svg" width="25" height="25"
                                         fill="currentColor"
                                         class="bi bi-eye-slash" viewBox="0 0 16 16">
                                        <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944
                                         5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83
                                          1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/>
                                        <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943
                                         1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
                                        <path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465
                                         1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0
                                         8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/>
                                    </svg> {{ app.user.login }} (non partagé)
                                </div>
                                <a style="padding : 0; padding-left: 15px" class="nav-link active"
                                   href="{{ path('app_logout') }}"><small>Changer de
                                        compte</small></a>
                            {% endif %}
                
                            <p style="color : red">* Champ obligatoire</p>
                        </div>
                    </div>
                
                    {# <div class="container tableauQuestions table-responsive" style="width: 75%"> #}
                    {# <table class="table"> #}
                    {# <thead> #}
                    {# <tr> #}
                    {# <th class="thCategorie"> #}
                    {# {% for categories in categorie1 %} #}
                    {# {{ categories.libelle }} : #}
                    {# {% endfor %} #}
                
                    {# #}{# {% for questions in question1 %} #}
                    {# #}{# <li>{{ questions.question }}</li> #}
                    {# #}{# {% endfor %} #}
                    {# </th> #}
                    {# </tr> #}
                    {# </thead> #}
                    {# {{ form_start(formFormulaire, {attr: {'novalidate': 'novalidate'}}) }} #}
                    {# <tbody class="table-hover"> #}
                    {# {% for reponse in formFormulaire.reponses %} #}
                    {# <tr> #}
                    {# <td> #}
                    {# #}{# TODO : ne pas afficher la catégorie si la même que la réponse précédente #}
                    {# #}{# <div>{{ reponse.vars.data.question.categories.libelle }}</div> #}
                    {# <div>{{ reponse.vars.data.question.question }}<span style="color: red"> *</span></div> #}
                    {# <br> #}
                    {# <div>{{ form_row(reponse.choice) }}</div> #}
                    {# <br> #}
                    {# <div>{{ form_row(reponse.commentaire) }}</div> #}
                    {# </td> #}
                    {# </tr> #}
                    {# {% endfor %} #}
                    {# </tbody> #}
                    {# </table> #}
                    {# <button type="submit" class="btn btn-success">Valider</button> #}
                    {# {{ form_end(formFormulaire) }} #}
                    {# </div> #}
                
                    {# <div> #}
                    {# {%  if listAllQuestions.categorie.id == 2 %} #}
                    {# {{ reponse.vars.data.question.question }} #}
                    {# {% endif %} #}
                    {# </div> #}
                
                
                
                
                    {# Espace de test fonctions twig #}
                    {# TODO  : PAGINATION #}
                
                    <div class="container">
                        <table>
                            <thead>
                                <tr>
                                    {% for categories in categorie1 %}
                                        {{ categories.libelle }} :
                                    {% endfor %}
                                </tr>
                            </thead>
                                {% for questions in question1 %}
                                    {% for reponse in formFormulaire.reponses %}
                                        <tbody>
                                            <tr>
                                                <td>
                                                    <div>
                                                            {{ form_row(reponse.choice) }}
                                                    </div>
                                    {% endfor %}
                                                    <div>
                                                        {{ questions.question }}
                                                    </div>
                                                </td>
                                            </tr>
                                        </tbody>
                                {% endfor %}
                        </table>
                    </div>
                
                {% endblock %}
                
                Ce ne sont que lignes pour test et en aucun cas un rendu final
                • Partager sur Facebook
                • Partager sur Twitter
                  29 novembre 2021 à 15:56:58

                  Ta boucle pour afficher le formulaire m'interpelle. Tu devrais boucler sur formFormulaire.reponses uniquement, et non sur question1 (qui plus est, le nom de la variable itérative qui est au pluriel, c'est moyennement logique à mon avis). Tu as un seul formulaire, mais tu tentes de l'afficher autant de fois qu'il y a d'éléments dans question1, d'où l'erreur.

                  Peut-être que tu te mélanges les pinceaux avec tes entités ? Là, formFormulaire contient une collection de Reponse, qui sont chacunes liées à une Question. A mon avis, tu as déjà autant de réponses que de questions, pas besoin de mettre une boucle supplémentaire sur question1, l'autre devrait suffire, de ce que je comprends.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    29 novembre 2021 à 16:10:28

                    Et bien oui j'arrive à afficher toutes mes questions avec la boucle formFormulaire.reponses et je peux y répondre sans souci néanmoins je voudrais pouvoir afficher la catégorie lorsque que celle-ci change, or avec ce que j'ai fais pour le moment il y a le formulaire complet en brut et c'est tout ce qui n'est pas le résultat que je souhaite obtenir, je peux afficher la catégorie avec 
                    {{ reponse.vars.data.question.categories.libelle }}

                    mais cela va afficher la catégorie à chaque question.

                    Exemple de ce que je souhaite obtenir : 

                    Catégorie1 : 

                    question 1

                    reponse 1 

                    question 2

                    réponse 2 

                    Catégorie 2 :

                    question 3 

                    réponse 3 

                    question 4

                    réponse 4 

                    etc etc etc 

                    -
                    Edité par AntoineMougenot 29 novembre 2021 à 16:11:06

                    • Partager sur Facebook
                    • Partager sur Twitter
                      29 novembre 2021 à 16:38:33

                      Vu que tu n'as jamais que les questions d'une seule catégorie, tu sors l'affichage de la question hors de la boucle. Comme le formulaire contient une liste de réponses, tu peux très bien prendre la catégorie de la première, donc accéder au premier élément du tableau, non ?

                      • Partager sur Facebook
                      • Partager sur Twitter
                        29 novembre 2021 à 17:25:07

                        Je n'ai pas tout à fait compris ce que vous vouliez me dire ..
                        • Partager sur Facebook
                        • Partager sur Twitter
                          30 novembre 2021 à 12:06:18

                          Par rapport au fait que tu as la catégorie qui s'affiche à chaque fois, tu as deux solutions :

                          • soit tu ne l'affiches que lors de la première itération de la boucle, mais ça implique de vérifier cela à chaque itération ;
                          • soit tu sors l'affichage de la boucle et tu affiches la catégorie de la question de la première réponse avant celle-ci.

                          Or, pour cette dernière option, tu as la possibilité technique de récupérer la première réponse dans formFormulaire — oui, il n'y a pas que les boucles pour accéder aux éléments d'une liste.
                          Tu peux aussi injecter dans le template la catégorie de la page et ainsi la manipuler comme une variable indépendante, peut-être que ce sera le plus simple.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            30 novembre 2021 à 12:18:27

                            Super merci beaucoup de votre aide, je me penche dessus, je vous communiquerais le résultat !
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Symfony 5, Pagination par id

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                            • Editeur
                            • Markdown