From a21cefab31f5d1e8a6ea0628604f26cce8cdd1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 14 Jul 2023 09:23:23 +0200 Subject: [PATCH] Fix: last fixes for accompanying period work filters - avoid errors when the user inverse date from and date to (we correct them) - allow the user to filter by multiple users - do not show filter by types if only one action type - more type-hinting in the $filter argument for AccompanyingPeriodWorkRepository::findByAccompanyingPeriodOpenFirst --- .../Templating/Listing/FilterOrderHelper.php | 10 +----- .../AccompanyingCourseWorkController.php | 24 ++++++++----- .../AccompanyingPeriodWorkRepository.php | 35 ++++++++++++++----- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php index 5c5d164fc..8bcc7ffae 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -14,21 +14,13 @@ namespace Chill\MainBundle\Templating\Listing; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\Listing\FilterOrderType; use DateTimeImmutable; -use Symfony\Component\Form\Extension\Core\Type\FormType; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\PropertyAccess\PropertyAccessor; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use Symfony\Component\PropertyAccess\PropertyPath; -use Symfony\Component\PropertyAccess\PropertyPathInterface; -use Symfony\Contracts\Translation\TranslatorInterface; use function array_merge; -use function count; -class FilterOrderHelper +final class FilterOrderHelper { private array $checkboxes = []; diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index 3eb6e67f5..66d020ad1 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -26,13 +26,14 @@ use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Form; +use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\Translation\TranslatorInterface; -class AccompanyingCourseWorkController extends AbstractController +final class AccompanyingCourseWorkController extends AbstractController { public function __construct( private readonly TranslatorInterface $trans, @@ -158,7 +159,7 @@ class AccompanyingCourseWorkController extends AbstractController $filter = $this->buildFilterOrder($period); $filterData = [ - 'types' => $filter->getEntityChoiceData('typesFilter'), + 'types' => $filter->hasEntityChoice('typesFilter') ? $filter->getEntityChoiceData('typesFilter') : [], 'before' => $filter->getDateRangeData('dateFilter')['to'], 'after' => $filter->getDateRangeData('dateFilter')['from'], 'user' => $filter->getUserPickerData('userFilter') @@ -203,7 +204,7 @@ class AccompanyingCourseWorkController extends AbstractController ]); } - private function createDeleteForm(int $id): Form + private function createDeleteForm(int $id): FormInterface { $params = []; $params['id'] = $id; @@ -217,16 +218,21 @@ class AccompanyingCourseWorkController extends AbstractController private function buildFilterOrder($associatedPeriod): FilterOrderHelper { - $filterBuilder = $this->filterOrderHelperFactory->create(self::class); $types = $this->workRepository->findActionTypeByPeriod($associatedPeriod); $filterBuilder - ->addDateRange('dateFilter', 'accompanying_course_work.date_filter') - ->addEntityChoice('typesFilter', 'accompanying_course_work.types_filter', \Chill\PersonBundle\Entity\SocialWork\SocialAction::class, $types, [ - 'choice_label' => fn (SocialAction $sa) => $this->translatableStringHelper->localize($sa->getTitle()) - ]) - ->addUserPicker('userFilter', 'accompanying_course_work.user_filter', ['required' => false, 'multiple' => false]) + ->addDateRange('dateFilter', 'accompanying_course_work.date_filter'); + + if (1 < count($types)) { + $filterBuilder + ->addEntityChoice('typesFilter', 'accompanying_course_work.types_filter', \Chill\PersonBundle\Entity\SocialWork\SocialAction::class, $types, [ + 'choice_label' => fn (SocialAction $sa) => $this->translatableStringHelper->localize($sa->getTitle()) + ]); + } + + $filterBuilder + ->addUserPicker('userFilter', 'accompanying_course_work.user_filter', ['required' => false]) ; return $filterBuilder->build(); diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php index 8c177f67c..56365452a 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php @@ -95,9 +95,9 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository * * then, closed works * * @return AccompanyingPeriodWork[] - * @param mixed $filters + * @param array{types?: list, user?: list, after?: null|\DateTimeImmutable, before?: null|\DateTimeImmutable} $filters */ - public function findByAccompanyingPeriodOpenFirst(AccompanyingPeriod $period, $filters, int $limit = 10, int $offset = 0): array + public function findByAccompanyingPeriodOpenFirst(AccompanyingPeriod $period, array $filters, int $limit = 10, int $offset = 0): array { $rsm = new ResultSetMappingBuilder($this->em); $rsm->addRootEntityFromClassMetadata(AccompanyingPeriodWork::class, 'w'); @@ -108,18 +108,32 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository // implement filters - if([] !== ($filters['types'] ?? [])) { + if ([] !== ($filters['types'] ?? [])) { $sql .= " AND w.socialaction_id IN (:types)"; } - if([] !== ($filters['user'] ?? [])) { - $sql .= " AND rw.user_id = :user"; + if ([] !== ($filters['user'] ?? [])) { + $sql .= " AND rw.user_id IN (" + . implode( + ', ', + // we add a user_xx for each key of the 'user' list + array_map(fn (User $u, int $idx) => ':user_' . $idx, $filters['user'], array_keys($filters['user'])) + ) + . ")"; } $sql .= " AND daterange(:after::date, :before::date) && daterange(w.startDate, w.endDate)"; - // set limit and offset + // if the start and end date were inversed, we inverse the order to avoid an error + if (null !== ($filters['after'] ?? null) && null !== ($filters['before']) && $filters['after'] > $filters['before']) { + $before = $filters['after']; + $after = $filters['before']; + } else { + $before = $filters['before']; + $after = $filters['after']; + } + // set limit and offset $sql .= " ORDER BY CASE WHEN enddate IS NULL THEN '-infinity'::timestamp ELSE 'infinity'::timestamp END ASC, startdate DESC, @@ -136,12 +150,15 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository $nq = $this->em->createNativeQuery($sql, $rsm) ->setParameter('periodId', $period->getId(), Types::INTEGER) ->setParameter('types', $typeIds) - ->setParameter('user', null !== $filters['user'] ? $filters['user']->getId() : null) - ->setParameter('after', ($filters['after'] ?? null)) - ->setParameter('before', ($filters['before'] ?? null)) + ->setParameter('after', $after) + ->setParameter('before', $before) ->setParameter('limit', $limit, Types::INTEGER) ->setParameter('offset', $offset, Types::INTEGER); + foreach ($filters['user'] as $key => $user) { + $nq->setParameter('user_' . $key, $user); + } + return $nq->getResult(); }