Browse Source

Filtres et pagination Ok

Sangfroid 3 weeks ago
parent
commit
fdaade9ad3

+ 0 - 27
src/Controller/FilmAbstractController.php

@@ -1,27 +0,0 @@
-<?php
-
-namespace App\Controller;
-
-use App\Dto\FiltersDTO;
-use App\Form\FiltersType;
-use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
-use Symfony\Component\Form\FormInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-abstract class FilmAbstractController extends AbstractController
-{
-    public function formPagination(Request $request): FormInterface
-    {
-        $session = $request->getSession();
-        
-        $filterDto = $session->get('filters', new FiltersDTO());
-        $filtersForm = $this->createForm(FiltersType::class, $filterDto);
-
-        $filtersForm->handleRequest($request);
-
-        if ($filtersForm->isSubmitted() && $filtersForm->isValid()) {
-            $session->set('filters', $filterDto);
-        }
-        return $filtersForm;
-    }
-}

+ 2 - 1
src/Controller/VideothequeCrudController.php

@@ -8,6 +8,7 @@ use App\Repository\FilmRepository;
 use App\Service\FilmManager;
 use App\Service\TmdbApiService;
 use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\Form\FormFactoryInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\Routing\Annotation\Route;
@@ -15,7 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Security\Http\Attribute\IsGranted;
 
-class VideothequeCrudController extends FilmAbstractController
+class VideothequeCrudController extends AbstractController
 {
     #[Route("/maliste/modifieravoir", name:"maliste_modifier_a_voir", methods: ['PATCH'])]
     public function modifierFilmDansListeAction(Request $request, EntityManagerInterface $em, FilmRepository $repo, FilmManager $filmManager): Response

+ 88 - 33
src/Controller/VideothequeListController.php

@@ -2,6 +2,7 @@
 
 namespace App\Controller;
 
+use App\Dto\FiltersDTO;
 use App\Entity\Commentaire;
 use App\Entity\Realisateur;
 use Symfony\Component\HttpFoundation\JsonResponse;
@@ -9,6 +10,7 @@ use Symfony\Component\Routing\Annotation\Route;
 use Symfony\Component\HttpFoundation\Request;
 use App\Entity\Genre;
 use App\Form\CommentaireType;
+use App\Form\FiltersType;
 use App\Repository\CommentaireRepository;
 use App\Repository\FilmRepository;
 use App\Repository\GenreRepository;
@@ -16,22 +18,33 @@ use App\Repository\RealisateurRepository;
 use App\Service\CommentaireManager;
 use App\Service\OptionsManager;
 use App\Service\Pagination;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\Form\FormFactoryInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Attribute\MapQueryString;
 
-class VideothequeListController extends FilmAbstractController
+class VideothequeListController extends AbstractController
 {
 	#[Route("/", name: "videotheque_liste")]
-	public function listeAction(Request $request, FilmRepository $filmRepository, OptionsManager $options): Response
+	public function listeAction(
+        Request $request,
+        FilmRepository $filmRepository,
+        OptionsManager $options,
+        #[MapQueryString]
+        ?FiltersDTO $filters,
+        FormFactoryInterface $formFactory,
+    ): Response
 	{
-        $page = (int)$request->get('p', 1);
-        $page = $page > 0 ? $page : 1;
-        if ($request->isMethod('POST')) {
-            $page = 1;
-        }
-        $filtersForm = $this->formPagination($request);
-        $qb = $filmRepository->queryTous($filtersForm->getData()->toArray(), $page);
-        $pagination = new Pagination($qb, $filtersForm->getData()->nbResults, $page);
+        $filters = $filters ?? new FiltersDTO();
+        $filtersForm = $formFactory->createNamed('', FiltersType::class, $filters);
+        
+        $filtersForm->handleRequest($request);
+        dump($filters);
+
+        $qb = $filmRepository->queryTous($filtersForm->getData()->page, $filtersForm->getData()->toArray());
+        $pagination = new Pagination($qb, $filtersForm->getData()->limit, $filtersForm->getData()->page);
 
 		return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
             'listeFilms'	=>	$pagination->getPaginator(),
@@ -42,15 +55,30 @@ class VideothequeListController extends FilmAbstractController
     }
 
     #[Route("/maliste", name:"videothequepersonnelle_maliste")]
-	public function maListeAction (Request $request, OptionsManager $options, FilmRepository $filmRepository): Response
+	public function maListeAction (
+        Request $request,
+        FilmRepository $filmRepository,
+        OptionsManager $options,
+        #[MapQueryString]
+        ?FiltersDTO $filters,
+        FormFactoryInterface $formFactory,
+    ): Response
     {
-        $filtersForm = $this->formPagination($request);
-        $listeFilms = $filmRepository->findTousFavoritesByUser($this->getUser(), $filtersForm->getData()->toArray());
-        return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
-            'listeFilms'    =>  $listeFilms,
+        $filters = $filters ?? new FiltersDTO();
+        $filters->userWantToView = $this->getUser();
+        $filtersForm = $formFactory->createNamed('', FiltersType::class, $filters);
+        
+        $filtersForm->handleRequest($request);
+
+        $qb = $filmRepository->queryTous($filtersForm->getData()->page, $filtersForm->getData()->toArray());
+        $pagination = new Pagination($qb, $filtersForm->getData()->limit, $filtersForm->getData()->page);
+
+		return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
+            'listeFilms'	=>	$pagination->getPaginator(),
             'titre'         =>  'Ma liste de films à voir',
-            'filtersForm'   => $filtersForm->createView()
-        ));
+            'filtersForm'   =>  $filtersForm->createView(),
+            'pagination'    =>  $pagination
+		));
     }
 
     #[Route("/prochaines-sorties", name: "prochaines_sorties")]
@@ -65,29 +93,56 @@ class VideothequeListController extends FilmAbstractController
     }
 
     #[Route("/liste-by/{id}", name: "videotheque_listepargenre")]
-	public function listeParGenreAction(Request $request, Genre $genre, FilmRepository $repo, OptionsManager $options): Response
+	public function listeParGenreAction(
+        Request $request,
+        Genre $genre,
+        FilmRepository $filmRepository,
+        OptionsManager $options,
+        #[MapQueryString]
+        ?FiltersDTO $filters,
+        FormFactoryInterface $formFactory,
+    ): Response
     {
-        $filtersForm = $this->formPagination($request);
-        $films = $repo->findFilmWithGenre([$genre->getName()], $filtersForm->getData()->toArray());
+        $filters = $filters ?? new FiltersDTO();
+        $filtersForm = $formFactory->createNamed('', FiltersType::class, $filters);
+        
+        $filtersForm->handleRequest($request);
 
-        return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
-            'listeFilms'    => $films,
-            'titre'         => 'Films par catégorie : '.$genre->getName(),
-            'filtersForm'   => $filtersForm
-        ));
+        $qb = $filmRepository->queryFilmWithGenre([$genre->getName()], $filtersForm->getData()->page, $filtersForm->getData()->toArray());
+        $pagination = new Pagination($qb, $filtersForm->getData()->limit, $filtersForm->getData()->page);
+
+		return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
+            'listeFilms'	=>	$pagination->getPaginator(),
+            'titre'         =>  'Films par genre : ' . $genre->getName(),
+            'filtersForm'   =>  $filtersForm->createView(),
+            'pagination'    =>  $pagination
+		));
     }
 
     #[Route("/liste-by_real/{id}", name: "videotheque_listeparreal")]
-    public function  listeParRealisateurAction(Request $request, Realisateur $realisateur, FilmRepository $repo, OptionsManager $options): Response
+    public function  listeParRealisateurAction(
+        Request $request,
+        Realisateur $realisateur,
+        FilmRepository $filmRepository,
+        OptionsManager $options,
+        #[MapQueryString]
+        ?FiltersDTO $filters,
+        FormFactoryInterface $formFactory,): Response
     {
-        $filtersForm = $this->formPagination($request);
-        $films = $repo->findFilmWithReal([$realisateur->getNomComplet()], $filtersForm->getData()->toArray());
+        $filters = $filters ?? new FiltersDTO();
+        $filtersForm = $formFactory->createNamed('', FiltersType::class, $filters);
+        
+        $filtersForm->handleRequest($request);
 
-        return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
-            'listeFilms'    => $films,
-            'titre'         => 'Films par réalisateur : '.$realisateur->getNomComplet(),
-            'filtersForm'   => $filtersForm
-        ));
+        $qb = $filmRepository->queryFilmWithReal([$realisateur->getNomComplet()], $filtersForm->getData()->page, $filtersForm->getData()->toArray());
+        $pagination = new Pagination($qb, $filtersForm->getData()->limit, $filtersForm->getData()->page);
+
+		return $this->render('videotheque/liste_'.$options->vue().'.html.twig', array(
+            'listeFilms'	=>	$pagination->getPaginator(),
+            'titre'         =>  'Films par réalisateur : ' . $realisateur->getNomComplet(),
+            'filtersForm'   =>  $filtersForm->createView(),
+            'pagination'    =>  $pagination
+		));
     }
 
 	#[Route("/fichefilm/{id}", name: "videotheque_voirfilm")]

+ 12 - 6
src/Dto/FiltersDTO.php

@@ -11,30 +11,36 @@ class FiltersDTO
         #[Assert\NotBlank()]
         #[Assert\GreaterThanOrEqual(10)]
         #[Assert\LessThanOrEqual(100)]
-        public int $nbResults = 25,
+        public int $limit = 25,
 
         public ?User $userName = null,
         
-        public ?int $note = null,
+        public null|int|string $note = 0,
         
         #[Assert\NotBlank()]
         public string $sortBy = 'dateSubmited',
 
         #[Assert\Choice(['ASC', 'DESC'])]
-        public string $sortOrder = 'DESC'
+        public string $sortOrder = 'DESC',
+
+        public ?User $userWantToView = null,
+
+        public int $page = 1
     )
     {
-
+        $this->note = $this->note === '' ? null : (int)$this->note;
     }
 
     public function toArray(): array
     {
         return [
-            'limit'     => $this->nbResults,
+            'limit'     => $this->limit,
             'username'  => $this->userName,
             'sortBy'    => $this->sortBy,
             'sortOrder' => $this->sortOrder,
-            'note'      => $this->note
+            'note'      => (int)$this->note,
+            'userWantToView' => $this->userWantToView,
+            'page'      => $this->page
         ];
     }
 }

+ 10 - 6
src/Form/FiltersType.php

@@ -22,9 +22,11 @@ class FiltersType extends AbstractType
                 'required'  => false,
                 'label'       => "Note au dessus de",
                 'attr'      => [
-                    'min'   => 0,
-                    'max'   => 5,
+                    'data-clear-value' => '0',
                     'class' => "rating",
+                    'data-min-threshold' => '0',
+                    'data-min'  => '0',
+                    'data-max'  => '5',
                     'data-step' => 1,
                     'data-show-clear'   => "true",
                     'data-show-caption' => "false",
@@ -32,7 +34,7 @@ class FiltersType extends AbstractType
                     'data-theme'          => "krajee-fa"
                 ],
             ])
-            ->add('nbResults', ChoiceType::class, [
+            ->add('limit', ChoiceType::class, [
                 'choices' => [
                     '10' => 10,
                     '25' => 25,
@@ -45,7 +47,7 @@ class FiltersType extends AbstractType
                 'class' => User::class,
                 'choice_label' => 'username',
                 'choice_value' => function(?User $user): string {
-                    return $user ? $user->getUserIdentifier() : '';
+                        return $user ? $user->getUsername() : '';
                 },
                 'query_builder' => function (UserRepository $er): QueryBuilder {
                     return $er->createQueryBuilder('u')
@@ -60,7 +62,7 @@ class FiltersType extends AbstractType
                     'Note' => 'note'
                 ]
             ])
-            ->add('sortOrder',ChoiceType::class, [
+            ->add('sortOrder', ChoiceType::class, [
                 'choices' => [
                     'ASC' => 'ASC',
                     'DESC' => 'DESC'
@@ -72,7 +74,9 @@ class FiltersType extends AbstractType
     public function configureOptions(OptionsResolver $resolver): void
     {
         $resolver->setDefaults([
-            'data_class' => FiltersDTO::class
+            'data_class'    => FiltersDTO::class,
+            'method'        => 'GET',
+            'csrf_protection' => false,
         ]);
     }
 }

+ 38 - 28
src/Repository/FilmRepository.php

@@ -5,7 +5,6 @@ namespace App\Repository;
 use App\Entity\Film;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 use Doctrine\ORM\QueryBuilder;
-use Doctrine\ORM\Tools\Pagination\Paginator;
 use Doctrine\Persistence\ManagerRegistry;
 
 /**
@@ -33,29 +32,45 @@ class FilmRepository extends ServiceEntityRepository
         return $query->getSingleResult();
     }
 
-    public function findFilmWithGenre(array $genreNames, array $filters = [], int $page) : QueryBuilder
+    public function queryFilmWithGenre(array $genreNames, int $page = 1, array $filters = []) : QueryBuilder
     {
-        $qb = $this->queryFilter($filters, $page);
+        $qb = $this->queryFilter($page, $filters);
         $qb
             ->innerJoin('f.genres', 'g')
             ->addSelect('f');
 
-        $qb->where($qb->expr()->in('g.name', $genreNames));
+        $qb->andWhere($qb->expr()->in('g.name', $genreNames));
 
         return $qb;
     }
 
-    public function findFilmWithReal(array $realisateursnames, array $filters = [], int $page): QueryBuilder
+    public function findFilmWithGenre(array $genreNames): array
     {
-        $qb = $this->queryFilter($filters, $page);
+        return $this->queryFilmWithGenre($genreNames)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+
+    public function queryFilmWithReal(array $realisateursNames, int $page = 1, array $filters = []): QueryBuilder
+    {
+        $qb = $this->queryFilter($page, $filters);
         $qb
             ->leftJoin('f.realisateurs', 'rea')
             ->addSelect('f')
-            ->where($qb->expr()->in('rea.nomComplet', $realisateursnames));
+            ->andWhere($qb->expr()->in('rea.nomComplet', $realisateursNames));
 
         return $qb;
     }
 
+    public function findFilmWithReal(array $realisateursNames): array
+    {
+        return $this->queryFilmWithReal($realisateursNames)
+            ->getQuery()
+            ->getResult()
+        ;
+    }
+
     public function findFilmWithRealLike($query): array
     {
         $qb = $this->createQueryBuilder('f');
@@ -85,25 +100,34 @@ class FilmRepository extends ServiceEntityRepository
             ->getResult();
     }
 
-    public function queryFilter(array $filters = [], int $page = 1): QueryBuilder
+    public function queryFilter(int $page = 1, array $filters = []): QueryBuilder
     {
         $qb =  $this->createQueryBuilder('f')
-            ->orderBy('f.'.($filters['sortBy'] ?? 'dateSubmited'), $filters['sortOrder'] ?? 'DESC');
+            ->orderBy('f.'.($filters['sortBy'] ?? 'dateSubmited'), $filters['sortOrder'] ?? 'DESC')
+        ;
 
-        if ($filters['limit']) {
+        if (!empty($filters['userWantToView'])) {
+            $qb
+                ->leftJoin('f.usersWantToView', 'wan')
+                ->andWhere($qb->expr()->in('wan', ':user'))
+                ->setParameter('user', $filters['userWantToView'])
+            ;
+        }
+
+        if (!empty($filters['limit'])) {
             $limit = (int)$filters['limit'];
             $qb->setFirstResult(($page * $limit) - $limit);
             $qb->setMaxResults($limit);
         }
     
-        if ($filters['note']) {
+        if (!empty($filters['note'])) {
             $qb
                 ->andWhere('f.note >= :note')
                 ->setParameter('note', $filters['note'])
             ;
         }    
         
-        if ($filters['username']) {
+        if (!empty($filters['username'])) {
             $qb
                 ->andWhere('f.authered = :authered')
                 ->setParameter('authered', $filters['username'])
@@ -113,26 +137,12 @@ class FilmRepository extends ServiceEntityRepository
         
     }
 
-    public function queryTous (array $filters = [], int $page): QueryBuilder
+    public function queryTous ($page = 1, array $filters = []): QueryBuilder
     {
-        $qb = $this->queryFilter($filters, $page)
-            ->leftJoin('f.authered', 'aut')->addSelect('aut')
-            ->leftJoin('f.genres', 'gen')->addSelect('gen')
-            ->leftJoin('f.realisateurs', 'rea')->addSelect('rea')
-        ;
-        return $qb;
-    }
-
-    public function queryTousFavoritesByUser($user, array $filters = [], int $page): QueryBuilder
-    {
-        $qb = $this->queryFilter($filters, $page);
-        $qb
+        $qb = $this->queryFilter($page, $filters)
             ->leftJoin('f.authered', 'aut')->addSelect('aut')
             ->leftJoin('f.genres', 'gen')->addSelect('gen')
             ->leftJoin('f.realisateurs', 'rea')->addSelect('rea')
-            ->leftJoin('f.usersWantToView', 'wan')
-            ->where($qb->expr()->in('wan', ':user'))
-            ->setParameter('user', $user)
         ;
         return $qb;
     }

+ 3 - 1
src/Service/Pagination.php

@@ -30,7 +30,9 @@ class Pagination
 
     public function getPages(): int
     {
-        return ceil($this->paginator->count() / $this->limit);
+        $pages = ceil($this->paginator->count() / $this->limit);
+        $pages = $pages > 0 ? $pages: 1;
+        return $pages;
     }
 
     public function getCurrentPage(): int

+ 1 - 1
templates/videotheque/_filters_form.html.twig

@@ -6,7 +6,7 @@
             {{ form_start(filtersForm, {'attr': {'class': 'row row-cols-lg-auto g-3 align-items-center'} } ) }}
         
             {{ form_row(filtersForm.note) }}
-            {{ form_row(filtersForm.nbResults) }}
+            {{ form_row(filtersForm.limit) }}
             {{ form_row(filtersForm.userName) }}
 
             {{ form_row(filtersForm.sortBy) }}

+ 24 - 3
templates/videotheque/_liste_footer.html.twig

@@ -1,11 +1,32 @@
 {% if pagination is defined %}
 <nav aria-label="pagination">
+    {% set param = app.request.attributes.get('_route_params')['id'] ?? '' %}
     <ul class="pagination">
-        <li class="page-item {{ pagination.getCurrentPage() > 1 ?: 'disabled' }}"><a class="page-link" href="{{ path(app.request.attributes.get('_route'), {'p': pagination.getCurrentPage() - 1}) }}">{{ "Previous" | trans }}</a></li>
+        <li class="page-item {{ pagination.getCurrentPage() > 1 ?: 'disabled' }}">
+            <a
+                class="page-link"
+                href="{{ path(app.request.attributes.get('_route'), app.request.query|merge({'id': param, 'page': pagination.getCurrentPage() - 1})) }}"
+            >
+                {{ "Previous" | trans }}
+            </a>
+        </li>
         {% for i in 1..pagination.getPages() %}
-        <li class="page-item {{ pagination.getCurrentPage() is not same as i ?: 'active'}}"><a class="page-link" href="{{ path(app.request.attributes.get('_route'), {'p': i}) }}">{{ i }}</a></li>
+        <li class="page-item {{ pagination.getCurrentPage() is not same as i ?: 'active'}}">
+            <a
+                class="page-link"
+                href="{{ path(app.request.attributes.get('_route'), app.request.query|merge({'id': param, 'page': i} )) }}"
+            >
+                {{ i }}
+            </a>
+        </li>
         {% endfor %}
-        <li class="page-item {{ pagination.getCurrentPage() < pagination.getPages() ?: 'disabled' }}"><a class="page-link" href="{{ path(app.request.attributes.get('_route'), {'p': pagination.getCurrentPage() + 1}) }}">{{ "Next" | trans }}</a></li>
+        <li class="page-item {{ pagination.getCurrentPage() < pagination.getPages() ?: 'disabled' }}">
+            <a
+                class="page-link" href="{{ path(app.request.attributes.get('_route'), app.request.query|merge({'id': param, 'page': pagination.getCurrentPage() + 1})) }}"
+            >
+                {{ "Next" | trans }}
+            </a>
+        </li>
     </ul>
 </nav>
 <div class="mb-6"></div>