From 3923a13b301ab60ac9df3d6b900a7e85c19f7486 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 15 Feb 2023 16:27:34 +0100 Subject: [PATCH 1/4] FEATURE [activity][filter] filter form created to list activities within the parcours and person context --- .../Controller/ActivityController.php | 9 ++ .../Form/ActivityFilterType.php | 107 ++++++++++++++++++ .../Activity/listAccompanyingCourse.html.twig | 43 ++++++- .../config/services/form.yaml | 3 + .../translations/messages.fr.yml | 2 + 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index b7d5fcbd2..e6bcdf836 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Controller; use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\ActivityReason; +use Chill\ActivityBundle\Form\ActivityFilterType; use Chill\ActivityBundle\Form\ActivityType; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityRepository; @@ -294,6 +295,10 @@ final class ActivityController extends AbstractController [$person, $accompanyingPeriod] = $this->getEntity($request); + $form = $this->createForm(ActivityFilterType::class); + + $form->handleRequest($request); + if ($person instanceof Person) { $this->denyAccessUnlessGranted(ActivityVoter::SEE, $person); $activities = $this->activityACLAwareRepository @@ -307,6 +312,7 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:listPerson.html.twig'; } elseif ($accompanyingPeriod instanceof AccompanyingPeriod) { + $this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod); $activities = $this->activityACLAwareRepository @@ -315,9 +321,12 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } + + return $this->render( $view, [ + 'form' => $form->createView(), 'activities' => $activities, 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php b/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php new file mode 100644 index 000000000..b38255a4f --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php @@ -0,0 +1,107 @@ +translatableString = $translatableString; + + $this->translator = $translator; + } + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + + $builder + ->add('types', EntityType::class, [ + 'class' => ActivityType::class, + 'label' => 'Activity type', + 'multiple' => true, + 'query_builder' => static function (EntityRepository $er) { + $qb = $er->createQueryBuilder('t'); + $qb->andWhere($qb->expr()->eq('t.active', "'TRUE'")); + + return $qb; + }, + 'choice_label' => function (ActivityType $t) { + return $this->translatableString->localize($t->getName()); + }, + 'required' => false, + ]) + ->add('jobs', EntityType::class, [ + 'class' => UserJob::class, + 'label' => 'user job', + 'multiple' => true, + 'query_builder' => static function (EntityRepository $er) { + $qb = $er->createQueryBuilder('j'); + $qb->andWhere($qb->expr()->eq('j.active', "'TRUE'")); + + return $qb; + }, + 'choice_label' => function (UserJob $j) { + return $this->translatableString->localize($j->getLabel()); + }, + 'required' => false, + ]) + ->add('dateFrom', ChillDateType::class, [ + 'label' => 'Activities after this date', + 'required' => false, + ]) + ->add('dateTo', ChillDateType::class, [ + 'label' => 'Activities before this date', + 'required' => false, + ]) + ->add('onlyMe', CheckboxType::class, [ + 'label' => 'My activities only', + 'required' => false, + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + + $form = $event->getForm(); + $dateFrom = $form->get('dateFrom')->getData(); + $dateTo = $form->get('dateTo')->getData(); + + // check that date_from is before date_to + if ( + (null !== $dateFrom && null !== $dateTo) + && $dateFrom >= $dateTo + ) { + $form->get('dateTo')->addError(new FormError( + $this->translator->trans('This date should be after ' + . 'the date given in "Implied in an activity after ' + . 'this date" field') + )); + } + + }); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + ]); + } + +} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig index a666f183d..7773d1728 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig @@ -27,7 +27,48 @@ {% set accompanying_course_id = accompanyingCourse.id %} {% endif %} -

{{ 'Activity list' |trans }}

+

{{ 'Activity list'|trans }}

+ +{#
#} + + {{ form_start(form) }} +
+
+ {{ form_label(form.types ) }} + {{ form_widget(form.types, {'attr': {'class': 'select2'}}) }} +
+
+ {{ form_label(form.jobs) }} + {{ form_widget(form.jobs, {'attr': {'class': 'select2'}}) }} +
+
+
+ {{ form_label(form.dateFrom) }} + {{ form_widget(form.dateFrom) }} +
+
+ {{ form_label(form.dateTo) }} + {{ form_widget(form.dateTo) }} +
+
+
+
+ {{ form_label(form.onlyMe) }} + {{ form_widget(form.onlyMe) }} +
+
+
+ + + + {{ form_end(form) }} +{#
#} {% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %} diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index f4945d8ce..d35cde222 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -1,5 +1,8 @@ --- services: + Chill\ActivityBundle\Form\ActivityFilterType: + autowire: true + autoconfigure: true Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategoryType: autowire: true autoconfigure: true diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 4dd67ceb8..f408de7fa 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -284,6 +284,8 @@ Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activ Filtered acp which has no activities: Filtrer les parcours sans activité associée Group acp by activity number: Grouper les parcours par nombre d’activité +My activities only: Mes échanges uniquement + #aggregators Activity type: Type d'activité Activity user: Utilisateur lié à l'activité From 1c80e0b5f5b76af315e9e7f43ef235f31e0829e5 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 15 Feb 2023 16:27:34 +0100 Subject: [PATCH 2/4] FEATURE [activity][filter] filter form created to list activities within the parcours and person context --- .../Controller/ActivityController.php | 9 ++ .../Form/ActivityFilterType.php | 107 ++++++++++++++++++ .../Activity/listAccompanyingCourse.html.twig | 43 ++++++- .../config/services/form.yaml | 3 + .../translations/messages.fr.yml | 2 + 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index b7d5fcbd2..e6bcdf836 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Controller; use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\ActivityReason; +use Chill\ActivityBundle\Form\ActivityFilterType; use Chill\ActivityBundle\Form\ActivityType; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityRepository; @@ -294,6 +295,10 @@ final class ActivityController extends AbstractController [$person, $accompanyingPeriod] = $this->getEntity($request); + $form = $this->createForm(ActivityFilterType::class); + + $form->handleRequest($request); + if ($person instanceof Person) { $this->denyAccessUnlessGranted(ActivityVoter::SEE, $person); $activities = $this->activityACLAwareRepository @@ -307,6 +312,7 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:listPerson.html.twig'; } elseif ($accompanyingPeriod instanceof AccompanyingPeriod) { + $this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod); $activities = $this->activityACLAwareRepository @@ -315,9 +321,12 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } + + return $this->render( $view, [ + 'form' => $form->createView(), 'activities' => $activities, 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php b/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php new file mode 100644 index 000000000..b38255a4f --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Form/ActivityFilterType.php @@ -0,0 +1,107 @@ +translatableString = $translatableString; + + $this->translator = $translator; + } + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + + $builder + ->add('types', EntityType::class, [ + 'class' => ActivityType::class, + 'label' => 'Activity type', + 'multiple' => true, + 'query_builder' => static function (EntityRepository $er) { + $qb = $er->createQueryBuilder('t'); + $qb->andWhere($qb->expr()->eq('t.active', "'TRUE'")); + + return $qb; + }, + 'choice_label' => function (ActivityType $t) { + return $this->translatableString->localize($t->getName()); + }, + 'required' => false, + ]) + ->add('jobs', EntityType::class, [ + 'class' => UserJob::class, + 'label' => 'user job', + 'multiple' => true, + 'query_builder' => static function (EntityRepository $er) { + $qb = $er->createQueryBuilder('j'); + $qb->andWhere($qb->expr()->eq('j.active', "'TRUE'")); + + return $qb; + }, + 'choice_label' => function (UserJob $j) { + return $this->translatableString->localize($j->getLabel()); + }, + 'required' => false, + ]) + ->add('dateFrom', ChillDateType::class, [ + 'label' => 'Activities after this date', + 'required' => false, + ]) + ->add('dateTo', ChillDateType::class, [ + 'label' => 'Activities before this date', + 'required' => false, + ]) + ->add('onlyMe', CheckboxType::class, [ + 'label' => 'My activities only', + 'required' => false, + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + + $form = $event->getForm(); + $dateFrom = $form->get('dateFrom')->getData(); + $dateTo = $form->get('dateTo')->getData(); + + // check that date_from is before date_to + if ( + (null !== $dateFrom && null !== $dateTo) + && $dateFrom >= $dateTo + ) { + $form->get('dateTo')->addError(new FormError( + $this->translator->trans('This date should be after ' + . 'the date given in "Implied in an activity after ' + . 'this date" field') + )); + } + + }); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + ]); + } + +} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig index a666f183d..7773d1728 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig @@ -27,7 +27,48 @@ {% set accompanying_course_id = accompanyingCourse.id %} {% endif %} -

{{ 'Activity list' |trans }}

+

{{ 'Activity list'|trans }}

+ +{#
#} + + {{ form_start(form) }} +
+
+ {{ form_label(form.types ) }} + {{ form_widget(form.types, {'attr': {'class': 'select2'}}) }} +
+
+ {{ form_label(form.jobs) }} + {{ form_widget(form.jobs, {'attr': {'class': 'select2'}}) }} +
+
+
+ {{ form_label(form.dateFrom) }} + {{ form_widget(form.dateFrom) }} +
+
+ {{ form_label(form.dateTo) }} + {{ form_widget(form.dateTo) }} +
+
+
+
+ {{ form_label(form.onlyMe) }} + {{ form_widget(form.onlyMe) }} +
+
+
+ +
    +
  • + +
  • +
+ + {{ form_end(form) }} +{#
#} {% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %} diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index f4945d8ce..d35cde222 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -1,5 +1,8 @@ --- services: + Chill\ActivityBundle\Form\ActivityFilterType: + autowire: true + autoconfigure: true Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategoryType: autowire: true autoconfigure: true diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 4dd67ceb8..f408de7fa 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -284,6 +284,8 @@ Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activ Filtered acp which has no activities: Filtrer les parcours sans activité associée Group acp by activity number: Grouper les parcours par nombre d’activité +My activities only: Mes échanges uniquement + #aggregators Activity type: Type d'activité Activity user: Utilisateur lié à l'activité From 7fd823f1ee3ce25f1d53a71816996f0a69cd7ed2 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 15 Feb 2023 18:39:22 +0100 Subject: [PATCH 3/4] FEATURE [repository] method added to repository to alter query using filters - not done --- .../Controller/ActivityController.php | 4 +- .../Repository/ActivityRepository.php | 52 ++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index e6bcdf836..46796c5e7 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -315,14 +315,14 @@ final class ActivityController extends AbstractController $this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod); + $data = $form->getData(); + $activities = $this->activityACLAwareRepository ->findByAccompanyingPeriod($accompanyingPeriod, ActivityVoter::SEE, 0, null, ['date' => 'DESC', 'id' => 'DESC']); $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } - - return $this->render( $view, [ diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityRepository.php index 5a6e16cd5..3519cf6fd 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityRepository.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityRepository.php @@ -12,10 +12,14 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Repository; use Chill\ActivityBundle\Entity\Activity; +use Chill\ActivityBundle\Entity\ActivityType; +use Chill\MainBundle\Entity\UserJob; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; +use Symfony\Component\Security\Core\Security; /** * @method Activity|null find($id, $lockMode = null, $lockVersion = null) @@ -25,9 +29,12 @@ use Doctrine\Persistence\ManagerRegistry; */ class ActivityRepository extends ServiceEntityRepository { - public function __construct(ManagerRegistry $registry) + private Security $security; + + public function __construct(ManagerRegistry $registry, Security $security) { parent::__construct($registry, Activity::class); + $this->security = $security; } /** @@ -97,4 +104,47 @@ class ActivityRepository extends ServiceEntityRepository return $qb->getQuery()->getResult(); } + + /** + * @param QueryBuilder $qb + * @param array|UserJob $jobs + * @param array|ActivityType $types + * @param \DateTime $dateFrom + * @param \DateTime $dateTo + * @param bool $onlyMe + * @return QueryBuilder + */ + private function addQueryFilters(QueryBuilder $qb, array $jobs, array $types, \DateTime $dateFrom, \DateTime $dateTo, bool $onlyMe): QueryBuilder + { + if (0 < count($jobs)) { + $qb->join('a.user', 'u'); + $qb->andWhere($qb->expr()->in('u.job', ':jobs')) + ->setParameter('jobs', $jobs); + } + + if (0 < count($types)) { + $qb->andWhere($qb->expr()->in('a.activityType', ':types')) + ->setParameter('types', $types); + } + + if (null !== $dateFrom && null !== $dateTo) + { + $qb->andWhere($qb->expr()->between( + 'a.date', + ':date_from', + ':date_to' + )) + ->setParameter('date_from', $dateFrom) + ->setParameter('date_to', $dateTo); + } + + if (true === $onlyMe) { + $currentUser = $this->security->getUser(); + + $qb->andWhere($qb->expr()->eq('a.user', ':currentUser')) + ->setParameter('currentUser', $currentUser); + } + + return $qb; + } } From 382d3ddd4262dd698843799399159d97ed80a9d6 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 15 Feb 2023 16:27:34 +0100 Subject: [PATCH 4/4] FEATURE [activity][filter] filter form created to list activities within the parcours and person context --- .../ChillActivityBundle/Controller/ActivityController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 46796c5e7..02ac23b2f 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -323,6 +323,8 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } + + return $this->render( $view, [