Symfony : barre de recherche dans la sidebar

Symfony : barre de recherche dans la sidebar

Comment créer une barre de recherche qui apparaitra directement dans la sidebar ou la navbar ?

Il est assez simple de créer une page de recherche et d'y mettre la barre de recherche. Tout se passe dans le même fichier.
Mais comment faire quand on a une barre de recherche dans la sidebar ou la navbar pour afficher les "bons résultats" sur la "bonne page" ?

1- Création d'un controller SearchController.php :

symfony console make:controller Search

 

Dans SearchController.php, on va directement créer une function searchBar avec le formulaire, juste en dessous de la function index() :

public function searchBar()
    {
        $form = $this->createFormBuilder()
            ->setAction($this->generateUrl('handleSearch'))
            ->add('query', TextType::class, [
                'label' => false,
                'attr' => [
                    'class' => 'form-control',
                    'placeholder' => 'Entrez un mot-clé'
                ]
            ])
            ->add('recherche', SubmitType::class, [
                'attr' => [
                    'class' => 'btn btn-primary'
                ]
            ])
            ->getForm();
        return $this->render('search/searchBar.html.twig', [
            'form' => $form->createView()
        ]);
    }

 

Ici, on crée le formulaire qui sera affiché dans la sidebar.
Avec un champ query (TextType) qui est le champ où on entre les mot-clés de recherche et un champ recherche (SubmitType) qui est en fait le bouton submit.
On "render" le template search/searchBar.html.twig.

Ensuite, dans ce controller, il faut gérer la requête. C'est la partie importante et plus "complexe" :

    /**
     * @Route("/handleSearch", name="handleSearch")
     * @param Request $request
     */
    public function handleSearch(Request $request, ArticleRepository $repo)
    {
        $query = $request->request->get('form')['query'];
        if($query) {
            $articles = $repo->findArticlesByName($query);
        }

        return $this->render('search/index.html.twig', [
            'articles' => $articles
        ]);
    }

 

On ajoute une @Route (handleSearch) qui va s'occuper de récupérer la funtion findArticlesByName() dans le ArticleRepository et va "render" le template search/index.html.twig.

2- Création d'une fonction de recherche dans le repository

Dans le repository ArticleRepository.php, on crée une function findArticlesByName()qui "ira chercher" les infos du title et du content (cela peut s'appeler titre et contenu chez vous : à adapter) :

    // Find/search articles by title/content
    public function findArticlesByName(string $query)
    {
        $qb = $this->createQueryBuilder('p');
        $qb
            ->where(
                $qb->expr()->andX(
                    $qb->expr()->orX(
                        $qb->expr()->like('p.title', ':query'),
                        $qb->expr()->like('p.content', ':query'),
                    ),
                    $qb->expr()->isNotNull('p.created_at')
                )
            )
            ->setParameter('query', '%' . $query . '%')
        ;
        return $qb
            ->getQuery()
            ->getResult();
    }

 

3- Les templates

Dans les templates, nous aurons search/searchBar.thml.twig avec seulement :

{{ form(form) }}

 

Et search/index.thml.twig qui aura notamment cette partie de code importante :

../..
{% if app.request.method == 'POST' %}
    <div>
        {% if articles | length == 0 %}
            <h4>Aucun résulat pour votre recherche.</h4>
           {% else %}
               <h3 class="mt-3">Vos résulats de recherche :</h3>
               {% for article in articles %}
                   <div class="mt-3 p-3 bg-light border rounded">
                       <a href="{{ path('article_show', {'slug': article.slug}) }}">
                              <h6 class="text-dark"><i class="bi bi-arrow-down-right-square-fill text-primary"></i> {{ article.title }}</h6>
                              <div class="text-dark small p-1 rounded">
                                    Posté le {{ article.createdAt|format_datetime('medium', 'short') }} par {{ article.author }}
                              </div>
                       </a>
                   </div>
              {% endfor %}
          {% endif %}
     </div>
{% endif %}

 

On vérifie qu'il y a une requête en POST et le nombre de résultats. Si articles | length == 0 il n'y a donc aucun résultat. Sinon, on boucle sur articles et on affiche les infos issues des articles "sélectionnés" par la requête de recherche.
Pour faire court, si on trouve le mot clé recherché dans un titre ou un contenu d'article, l'article est "sélectionné".

Enfin, il faut afficher la barre de recherche (soit dans la sidebar, soit dans la navbar) en faisant un "render" de controller et en choisissant la function searchBar :

{{ render(controller(
        'App\\Controller\\SearchController::searchBar'
 )) }}

 

Voila : vous devriez avoir une barre de recherche accessible depuis la sidebar ou la navbar et qui renvoie les résultats sur la page search/index.html.twig.

citizenz7
Posté par citizenz7

Geek quinqua nivernais fan d'ovalie, de linuxerie, de musique et de Net

10 commentaires

tuxyJeff Répondre

Merci !

die488 Répondre

Merci pour ce tuto, j'ai pu m'en inspirer pour un projet. Je ne vois par contre pas comment trimmer le champ avant que la recherche ne s'effectue et éviter de la sorte les recherches du type " ". J'ai pourtant ces attributs dans mon contrôleur ->add('query', TextType::class, [ 'label' => false, 'attr' => [ 'class' => 'form-control', 'placeholder' => 'Entrez un mot-clé', 'trim' => true, 'required' => true, 'minlength' => 3 ] ]) une idée ?

citizenz7

Désolé, je ne sais pas quoi vous répondre... je ne connaissais même pas 'trim' => true :D

Giteau53 Répondre

Bonjour, j'ai un erreur sur le render : An exception has been thrown during the rendering of a template ("Could not load type "App\Controller\TextType": class does not exist."). Je ne comprend pas j'ai bien suvi le tuto.

simon

Il faut ajouter le use pour la class textype utilisée dans le form....clic droit sur TextType::class et importer a classe...il faut qu'elle soit dan les use en haut....

Simon

SI tu n'a pas le clic droit et que tu utilises VSC installe l'extension : PHP Namespace Resolver ça va le faire...

citizenz7 Répondre

Merci Simon pour ton aide ;)

Jay75 Répondre

Bonjour, Merci pour ce tutoriel, j'ai juste une erreur quand je soumet la recherche, (Input value "form" contains a non-scalar value.) merci par avance pour votre réponse.

citizenz

Effectivement... depuis l'arrivée de Symfony 6, il semblerait que "quelque chose" a changé. Je n'ai pas de réponse pour le moment mais si quelqu'un en a une, n'hésitez pas à la déposer ici :D

Roxas027

Bonjour, la fonction get ne peut plus utiliser les tableau depuis symfony 6, il faut donc modifier "$request->request->get('form')['query']" par: "$request->request->all('form')['query'] all qui est une fonction qui récupère les tableau

Laisser un commentaire

Votre adresse email ne sera pas publiée.

Email:
Pseudo:
Message:
Accepter les CGU
Recopiez le code antispam: