11 août 2022 | Connexion

Blog

Symfony : barre de recherche dans la sidebar

Symfony : barre de recherche dans la sidebar

Développement web
Symfony PHP Twig

il y a 1 an citizenz7 10 commentaires 12059 lectures

Merci de lire les commentaires de cet article. Notamment celui de Roxas027 qui donne la solution à l'erreur "Input value "form" contains a non-scalar value".

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.

10 commentaires


die488, le 22-10-2021 à 22:43:22

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, le 24-10-2021 à 17:15:13

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

Giteau53, le 08-04-2022 à 11:14:36

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, le 08-04-2022 à 21:51:23

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, le 08-04-2022 à 21:55:12

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

citizenz7, le 11-04-2022 à 17:25:48

Merci Simon pour ton aide ;)

Jay75, le 13-04-2022 à 10:04:35

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, le 06-05-2022 à 07:57:02

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, le 09-05-2022 à 13:41:22

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

citizenz7, le 30-07-2022 à 11:15:33

Avec énormément de retard : merci @Roxas027 pour cette précision très utile.

Nb d'articles actifs : 38 | Nb de commentaires : 13 | Nb de catégories : 7 | Nb de tags : 32 | Nb total de lectures : 107 109
2022 citizenz.info • Some rights reserved GPLv3 • Version 3.3.2

Faut arrêter ces conneries de nord et de sud ! Une fois pour toutes, le nord, suivant comment on est tourné, ça change tout ! (Perceval, Kaamelott, Livre I, Ambidextrie)