From 97dbc4bc168a5b8da6dd8f6672da3019b9e542ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 28 Oct 2021 00:11:05 +0200 Subject: [PATCH] add more filtering possibilities with order helper --- .../Form/Type/Listing/FilterOrderType.php | 11 +- .../views/FilterOrder/base.html.twig | 31 ++++-- .../Templating/Listing/FilterOrderHelper.php | 45 +++++--- .../Controller/SingleTaskController.php | 15 ++- .../SingleTaskAclAwareRepository.php | 102 ++++++++++-------- .../translations/messages.fr.yml | 2 +- 6 files changed, 127 insertions(+), 79 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php index 3bbd6b9ae..564b08596 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php @@ -32,6 +32,7 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType ]); } + $checkboxesBuilder = $builder->create('checkboxes', null, [ 'compound' => true ]); foreach ($helper->getCheckboxes() as $name => $c) { $choices = \array_combine( @@ -42,17 +43,21 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType $c['choices'] ); - $builder->add('c_'.$name, ChoiceType::class, [ + $checkboxesBuilder->add($name, ChoiceType::class, [ 'choices' => $choices, 'expanded' => true, 'multiple' => true, ]); } + if (0 < count($helper->getCheckboxes())) { + $builder->add($checkboxesBuilder); + } + foreach ($this->requestStack->getCurrentRequest()->query->getIterator() as $key => $value) { switch($key) { case 'q': - case 'c_'.$key: + case 'checkboxes'.$key: break; case 'page': $builder->add($key, HiddenType::class, [ @@ -75,7 +80,7 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType $view->vars['has_search_box'] = $helper->hasSearchBox(); $view->vars['checkboxes'] = []; foreach ($helper->getCheckboxes() as $name => $c) { - $view->vars['checkboxes']['c_'.$name] = []; + $view->vars['checkboxes'][$name] = []; } } diff --git a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig index 8358d0e9b..3457c883a 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig @@ -10,17 +10,30 @@ {% endif %} - {% for checkbox_name, options in form.vars.checkboxes %} -
-
- {{ form_widget(form[checkbox_name]) }} + {% if form.checkboxes|length > 0 %} + {% for checkbox_name, options in form.checkboxes %} +
+
+ {% for c in form['checkboxes'][checkbox_name].children %} +
+ {{ form_widget(c) }} + {{ form_label(c) }} +
+ {% endfor %} +
{% if loop.last %} -
- -
+
+
+
    +
  • + +
  • +
+
+
{% endif %} -
- {% endfor %} + {% endfor %} + {% endif %}
{{ form_end(form) }} diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php index ffd601b91..0a28d39ca 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -13,6 +13,11 @@ class FilterOrderHelper private RequestStack $requestStack; private ?array $searchBoxFields = null; private array $checkboxes = []; + private ?array $submitted = null; + private ?string $formName = 'filter'; + private string $formType = FilterOrderType::class; + private array $formOptions = []; + public function __construct( FormFactoryInterface $formFactory, @@ -45,10 +50,9 @@ class FilterOrderHelper return $this; } - public function getCheckbox(string $name): array + public function getCheckboxData(string $name): array { - return $this->requestStack->getCurrentRequest() - ->query->get('c_'.$name, $this->checkboxes[$name]['default']); + return $this->getFormData()['checkboxes'][$name]; } public function getCheckboxes(): array @@ -63,12 +67,23 @@ class FilterOrderHelper private function getFormData(): array { - $r = [ - 'q' => $this->getQueryString(), - ]; + if (NULL === $this->submitted) { + $this->submitted = $this->buildForm() + ->getData(); + } + return $this->submitted; + } + + private function getDefaultData(): array + { + $r = []; + + if ($this->hasSearchBox()) { + $r['q'] = ''; + } foreach ($this->checkboxes as $name => $c) { - $r[$name] = $this->getCheckbox($name); + $r['checkboxes'][$name] = $c['default']; } return $r; @@ -76,21 +91,17 @@ class FilterOrderHelper public function getQueryString(): ?string { - $q = $this->requestStack->getCurrentRequest() - ->query->get('q', null); - - return empty($q) ? NULL : $q; + return $this->getFormData()['q']; } - public function buildForm($name = null, string $type = FilterOrderType::class, array $options = []): FormInterface + public function buildForm(): FormInterface { - $form = $this->formFactory - ->createNamed($name, $type, $this->getFormData(), \array_merge([ + return $this->formFactory + ->createNamed($this->formName, $this->formType, $this->getDefaultData(), \array_merge([ 'helper' => $this, 'method' => 'GET', 'csrf_protection' => false, - ], $options)); - - return $form; + ], $this->formOptions)) + ->handleRequest($this->requestStack->getCurrentRequest()); } } diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index 90dbe4744..359dc8909 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -532,14 +532,18 @@ final class SingleTaskController extends AbstractController $this->denyAccessUnlessGranted('ROLE_USER'); $filterOrder = $this->buildFilterOrder(); + $flags = \array_merge( + $filterOrder->getCheckboxData('status'), + \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) + ); $nb = $this->singleTaskAclAwareRepository->countByCurrentUsersTasks( $filterOrder->getQueryString(), - $filterOrder->getCheckbox('status') + $flags ); $paginator = $this->paginatorFactory->create($nb); $tasks = $this->singleTaskAclAwareRepository->findByCurrentUsersTasks( $filterOrder->getQueryString(), - $filterOrder->getCheckbox('status'), + $flags, $paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage() ); @@ -555,14 +559,19 @@ final class SingleTaskController extends AbstractController { $statuses = ['no-alert', 'warning', 'alert']; $statusTrans = [ + 'Tasks without alert', 'Tasks near deadline', 'Tasks over deadline', - 'Tasks without alert', + ]; + $states = [ + // todo: get a list of possible states dynamically + 'new', 'in_progress', 'closed', 'canceled' ]; return $this->filterOrderHelperFactory ->create(self::class) ->addSearchBox() ->addCheckbox('status', $statuses, $statuses, $statusTrans) + ->addCheckbox('states', $states, ['new', 'in_progress']) ->build() ; } diff --git a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php index b034bf973..2e5b8d803 100644 --- a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php +++ b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php @@ -63,64 +63,74 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository if (!empty($pattern)) { $qb->andWhere($qb->expr()->like('LOWER(UNACCENT(t.title))', 'LOWER(UNACCENT(:pattern))')) - ->setParameter('pattern', $pattern) + ->setParameter('pattern', '%'.$pattern.'%') ; } if (count($flags) > 0) { - $orX = $qb->expr()->orX(); + $orXDate = $qb->expr()->orX(); + $orXState = $qb->expr()->orX(); $now = new \DateTime(); - if (\in_array('no-alert', $flags)) { - $orX - ->add( - $qb->expr()->orX( - $qb->expr()->isNull('t.endDate'), - $qb->expr()->gte('t.endDate - COALESCE(t.warningInterval, :intervalBlank)', ':now') - ) - ); - $qb - ->setParameter('intervalBlank', new \DateInterval('P0D')) - ->setParameter('now', $now) - ; + foreach ($flags as $key => $flag) { + switch ($flag) { + case 'no-alert': + $orXDate + ->add( + $qb->expr()->orX( + $qb->expr()->isNull('t.endDate'), + $qb->expr()->gte('t.endDate - COALESCE(t.warningInterval, :intervalBlank)', ':now') + ) + ); + $qb + ->setParameter('intervalBlank', new \DateInterval('P0D')) + ->setParameter('now', $now); + break; + case 'warning': + $orXDate + ->add( + $qb->expr()->andX( + $qb->expr()->not($qb->expr()->isNull('t.endDate')), + $qb->expr()->not($qb->expr()->isNull('t.warningInterval')), + $qb->expr()->gte('t.endDate - t.warningInterval', ':now'), + $qb->expr()->lt('t.endDate', ':now') + ) + ); + $qb + ->setParameter('now', $now); + break; + case 'alert': + $orXDate + ->add( + $qb->expr()->andX( + $qb->expr()->not($qb->expr()->isNull('t.endDate')), + $qb->expr()->lte('t.endDate', ':now') + ) + ); + $qb + ->setParameter('now', $now); + break; + case \substr($flag, 0, 6) === 'state_': + $state = \substr($flag, 6); + $orXState + ->add( + "JSONB_EXISTS_IN_ARRAY(t.currentStates, :state_$key) = 'TRUE'" + ); + $qb->setParameter("state_$key", $state); + break; + default: + throw new \LogicException("this flag is not supported: $flag"); + } } - if (\in_array('warning', $flags)) { - $orX - ->add( - $qb->expr()->andX( - $qb->expr()->eq('t.closed', "'FALSE'"), - $qb->expr()->not($qb->expr()->isNull('t.endDate')), - $qb->expr()->not($qb->expr()->isNull('t.warningInterval')), - $qb->expr()->lte('t.endDate - t.warningInterval', ':now') - ) - ) - ; - $qb - ->setParameter('now', $now) - ; + if ($orXDate->count() > 0) { + $qb->andWhere($orXDate); } - - if (\in_array('alert', $flags)) { - $orX - ->add( - $qb->expr()->andX( - $qb->expr()->eq('t.closed', "'FALSE'"), - $qb->expr()->not($qb->expr()->isNull('t.endDate')), - $qb->expr()->lte('t.endDate', ':now') - ) - ) - ; - $qb - ->setParameter('now', $now) - ; + if ($orXState->count() > 0) { + $qb->andWhere($orXState); } - - $qb->andWhere($orX); } - - return $qb; } diff --git a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml index 0b9ef6251..5633c0219 100644 --- a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml @@ -99,7 +99,7 @@ Are you sure you want to start this task ?: Êtes-vous sûrs de vouloir démarre Tasks near deadline: Tâches à échéance proche Tasks over deadline: Tâches à échéance dépassée -Tasks without alert: Tâches sans alerte +Tasks without alert: Tâches à échéance future ou sans échéance #title My tasks near deadline: Mes tâches à échéance proche