0d2b5ce6de2f — Eddie Barraco 5 years ago
Make tag filter works
7 files changed, 120 insertions(+), 64 deletions(-)

M config/packages/twig.yaml
M src/Controller/ArticleController.php
R src/Form/TagFilterType.php => 
A => src/Form/TagLabelFilterType.php
M src/Repository/ArticleRepository.php
M templates/article/archive.html.twig
R templates/forms/themes.html.twig => 
M config/packages/twig.yaml +0 -2
@@ 2,5 2,3 @@ twig:
     default_path: '%kernel.project_dir%/templates'
     debug: '%kernel.debug%'
     strict_variables: '%kernel.debug%'
-    form_themes:
-        - 'forms/themes.html.twig'

          
M src/Controller/ArticleController.php +18 -5
@@ 3,7 3,7 @@ 
 namespace App\Controller;
 
 use App\Entity\Article;
-use App\Form\TagFilterType;
+use App\Form\TagLabelFilterType;
 use App\Repository\ArticleRepository;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\Request;

          
@@ 24,12 24,25 @@ class ArticleController extends Abstract
         ]);
     }
 
-    public function showArchive(?int $page = 0)
+    public function showArchive(Request $request, ?int $page = 0)
     {
-        $pageCount = $this->articleRepository->getPageCount();
-        $articles = $this->articleRepository->findPaginatedOrdered($page);
+        $itemPerPage = 10;
+        $tagLabelsFilter = [];
+        $qb = null;
 
-        $form = $this->createForm(TagFilterType::class);
+        $form = $this->createForm(TagLabelFilterType::class);
+        $form->handleRequest($request);
+        if ($form->isSubmitted() && $form->isValid()) {
+            $tagLabelsFilter = $form->getData()['labels'];
+            $qb = $this->articleRepository->findByTagLabelsQueryBuilder($tagLabelsFilter, 'a');
+        }
+
+        $pageCount = ceil($this->articleRepository->getCount('a', $qb) / $itemPerPage);
+
+        $qb = $this->articleRepository->lastFirstQueryBuilder('a', $qb);
+        $qb = $this->articleRepository->paginateQueryBuilder($page, $itemPerPage, 'a', $qb);
+
+        $articles = $qb->getQuery()->execute();
 
         return $this->render('article/archive.html.twig', [
             'articles' => $articles,

          
R src/Form/TagFilterType.php =>  +0 -32
@@ 1,32 0,0 @@ 
-<?php
-
-namespace App\Form;
-
-use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\CallbackTransformer;
-use Symfony\Component\Form\Extension\Core\Type;
-use Symfony\Component\Form\FormBuilderInterface;
-
-class TagFilterType extends AbstractType
-{
-    public function buildForm(FormBuilderInterface $builder, array $options)
-    {
-        $builder
-            ->add('tags', Type\TextType::class, [
-                'label' => 'tags'
-            ])
-            //->addModelTransformer(new CallbackTransformer(
-            //    function ($tagsAsEntities) {
-            //        dump($tagsAsEntities);
-            //        // transform the array to a string
-            //        return implode(', ', $tagsAsEntities);
-            //    },
-            //    function ($tagsAsString) {
-            //        dump($tagsAsString);
-            //        // transform the string back to an array
-            //        return explode(', ', $tagsAsString);
-            //    }
-            //))
-        ;
-    }
-}

          
A => src/Form/TagLabelFilterType.php +45 -0
@@ 0,0 1,45 @@ 
+<?php
+
+namespace App\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\CallbackTransformer;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\Extension\Core\Type;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class TagLabelFilterType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('labels', Type\TextType::class, [
+                'label' => false,
+                'required' => false,
+                'attr' => [
+                    'placeholder' => 'tags'
+                ]
+            ])
+            ->get('labels')
+            ->addModelTransformer(new CallbackTransformer(
+                function ($tagsAsArray) {
+                    return null;
+                },
+                function ($tagsAsString) {
+                    if (null === $tagsAsString) {
+                        return [];
+                    }
+                    return explode(' ', $tagsAsString);
+                }
+            ))
+        ;
+    }
+
+    public function configureOptions(OptionsResolver $resolver)
+    {
+        $resolver->setDefaults([
+            'method' => 'get',
+            'csrf_protection' => false,
+        ]);
+    }
+}

          
M src/Repository/ArticleRepository.php +55 -18
@@ 4,6 4,7 @@ namespace App\Repository;
 
 use App\Entity\Article;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\ORM\QueryBuilder;
 use Symfony\Bridge\Doctrine\RegistryInterface;
 
 class ArticleRepository extends ServiceEntityRepository

          
@@ 13,27 14,63 @@ class ArticleRepository extends ServiceE
         parent::__construct($registry, Article::class);
     }
 
-    public function getPageCount(?int $itemPerPage = 5): int
+    public function paginateQueryBuilder(int $page, int $itemPerPage, ?string $alias = 'a', ?QueryBuilder $qb = null): QueryBuilder
+    {
+        if (null === $qb) {
+            $qb = $this->createQueryBuilder($alias);
+        }
+
+        return $qb
+            ->setFirstResult($page * $itemPerPage)
+            ->setMaxResults($itemPerPage)
+        ;
+    }
+
+    public function lastFirstQueryBuilder(?string $alias = 'a', ?QueryBuilder $qb = null): QueryBuilder
+    {
+        if (null === $qb) {
+            $qb = $this->createQueryBuilder($alias);
+        }
+
+        return $qb
+            ->orderBy(sprintf('%s.createdAt', $alias), 'DESC')
+        ;
+    }
+
+    public function findByTagLabelsQueryBuilder(array $tagLabels, ?string $alias = 'a', ?QueryBuilder $qb = null): QueryBuilder
     {
-        $count = $this
-            ->createQueryBuilder('a')
-            ->select('count(a.id)')
+        if (null === $qb) {
+            $qb = $this->createQueryBuilder($alias);
+        }
+
+        foreach ($tagLabels as $tagLabel) {
+            $tagJoin = sprintf('t%d', uniqid(rand()));
+            $qb
+                ->join(
+                    sprintf('%s.tags', $alias),
+                    $tagJoin,
+                    'WITH',
+                    sprintf('%s.label = :tagLabel%s', $tagJoin, $tagJoin)
+                )
+                ->setParameter(sprintf('tagLabel%s', $tagJoin), $tagLabel)
+            ;
+        }
+
+        return $qb;
+    }
+
+    public function getCount(?string $alias = 'a', ?QueryBuilder $qb = null): int
+    {
+        if (null === $qb) {
+            $qb = $this->createQueryBuilder($alias);
+        } else {
+            $qb = clone $qb;
+        }
+
+        return $qb
+            ->select(sprintf('count(%s.id)', $alias))
             ->getQuery()
             ->getSingleScalarResult()
         ;
-
-        return ceil($count / $itemPerPage);
-    }
-
-    public function findPaginatedOrdered(?int $page = 0, ?int $itemPerPage = 5): array
-    {
-        return $this
-            ->createQueryBuilder('a')
-            ->setFirstResult($page * $itemPerPage)
-            ->setMaxResults($itemPerPage)
-            ->orderBy('a.createdAt', 'DESC')
-            ->getQuery()
-            ->execute()
-        ;
     }
 }

          
M templates/article/archive.html.twig +2 -2
@@ 16,12 16,12 @@ 
 
         <div class="pagination">
             {% if 0 < page %}
-                <a href="{{ path('article_archive', {'page': page-1}) }}">Page {{ page-1 }}</a>
+                <a href="{{ path('article_archive', app.request.query.all|merge({'page': page-1})) }}">Page {{ page-1 }}</a>
             {% else %}
                 <span></span>
             {% endif %}
             {% if page + 1 < pageCount %}
-                <a href="{{ path('article_archive', {'page': page+1}) }}">Page {{ page+1 }}</a>
+                <a href="{{ path('article_archive', app.request.query.all|merge({'page': page+1})) }}">Page {{ page+1 }}</a>
             {% else %}
                 <span></span>
             {% endif %}

          
R templates/forms/themes.html.twig =>  +0 -5
@@ 1,5 0,0 @@ 
-{% block tag_filter_widget %}
-    <div>
-        {{ form_widget(form.tags, {'attr': {'placeholder': form.tags.vars.label}}) }}
-    </div>
-{% endblock %}