From 11fb9bcd0b170143a82d78fc1fc8390186f609d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 18 Oct 2023 16:03:26 +0200 Subject: [PATCH] [export] add a filter and aggregator on activities: filter/group by persons taking part to the activity --- .../unreleased/Feature-20231018-160235.yaml | 6 ++ .../Export/Aggregator/PersonsAggregator.php | 78 +++++++++++++++++ .../Export/Filter/PersonsFilter.php | 87 +++++++++++++++++++ .../Aggregator/PersonsAggregatorTest.php | 60 +++++++++++++ .../Tests/Export/Filter/PersonsFilterTest.php | 72 +++++++++++++++ .../config/services/export.yaml | 8 ++ .../translations/messages.fr.yml | 7 ++ .../Export/Helper/LabelPersonHelper.php | 15 ++++ 8 files changed, 333 insertions(+) create mode 100644 .changes/unreleased/Feature-20231018-160235.yaml create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php create mode 100644 src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php diff --git a/.changes/unreleased/Feature-20231018-160235.yaml b/.changes/unreleased/Feature-20231018-160235.yaml new file mode 100644 index 000000000..87fe1de0c --- /dev/null +++ b/.changes/unreleased/Feature-20231018-160235.yaml @@ -0,0 +1,6 @@ +kind: Feature +body: '[export] add a filter and aggregator on activites: group/filter activities + by people participating to the exchange' +time: 2023-10-18T16:02:35.99265091+02:00 +custom: + Issue: "172" diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php new file mode 100644 index 000000000..8459741c5 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonsAggregator.php @@ -0,0 +1,78 @@ +labelPersonHelper->getLabel($key, $values, 'export.aggregator.activity.by_persons.Persons'); + } + + public function getQueryKeys($data) + { + return [self::PREFIX.'_pid']; + } + + public function getTitle() + { + return 'export.aggregator.activity.by_persons.Group activity by persons'; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = self::PREFIX; + + $qb + ->leftJoin('activity.persons', "{$p}_p") + ->addSelect("{$p}_p.id AS {$p}_pid") + ->addGroupBy("{$p}_pid"); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php new file mode 100644 index 000000000..8bdefeb24 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonsFilter.php @@ -0,0 +1,87 @@ +expr()->orX(); + + foreach (array_values($data['accepted_persons']) as $key => $person) { + $orX->add($qb->expr()->isMemberOf(":{$p}_p_{$key}", 'activity.persons')); + $qb->setParameter(":{$p}_p_{$key}", $person); + } + + $qb->andWhere($orX); + } + + public function applyOn() + { + return Declarations::ACTIVITY; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('accepted_persons', PickPersonDynamicType::class, [ + 'multiple' => true, + 'label' => 'export.filter.activity.by_persons.persons taking part on the activity', + ]); + } + + public function getFormDefaultData(): array + { + return [ + 'accepted_persons' => [], + ]; + } + + public function describeAction($data, $format = 'string') + { + $users = []; + + foreach ($data['accepted_persons'] as $u) { + $users[] = $this->personRender->renderString($u, []); + } + + return ['export.filter.activity.by_persons.Filtered activity by persons: only %persons%', [ + '%persons%' => implode(', ', $users), + ]]; + } + + public function getTitle(): string + { + return 'export.filter.activity.by_persons.Filter activity by persons'; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php new file mode 100644 index 000000000..b067e308d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/PersonsAggregatorTest.php @@ -0,0 +1,60 @@ +labelPersonHelper = self::$container->get(LabelPersonHelper::class); + } + + public function getAggregator() + { + return new PersonsAggregator($this->labelPersonHelper); + } + + public function getFormData() + { + return [ + [], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + return [ + $em->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity'), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php new file mode 100644 index 000000000..cefc226e7 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonsFilterTest.php @@ -0,0 +1,72 @@ +personRender = self::$container->get(PersonRenderInterface::class); + } + + public function getFilter() + { + return new PersonsFilter($this->personRender); + } + + public function getFormData() + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $persons = $em->createQuery('SELECT p FROM '.Person::class.' p ') + ->setMaxResults(2) + ->getResult(); + + self::ensureKernelShutdown(); + + return [ + [ + 'accepted_persons' => $persons, + ], + ]; + } + + public function getQueryBuilders() + { + self::bootKernel(); + + $em = self::$container->get(EntityManagerInterface::class); + + yield $em->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity'); + + self::ensureKernelShutdown(); + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 09a5227eb..3bb3b3695 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -200,3 +200,11 @@ services: Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator: tags: - { name: chill.export_aggregator, alias: activity_sentreceived_aggregator } + + Chill\ActivityBundle\Export\Filter\PersonsFilter: + tags: + - { name: chill.export_filter, alias: activity_by_persons_filter } + + Chill\ActivityBundle\Export\Aggregator\PersonsAggregator: + tags: + - { name: chill.export_aggregator, alias: activity_by_persons_aggregator } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 123a0d075..9c84e1815 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -377,6 +377,10 @@ export: by_creator_scope: Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange 'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%" + by_persons: + Filter activity by persons: Filtrer les échanges par usager participant + 'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%' + persons taking part on the activity: Usagers participants à l'échange aggregator: activity: @@ -400,6 +404,9 @@ export: by_creator_job: Group activity by creator job: Grouper les échanges par service du créateur de l'échange Calc date: Date de calcul du service du créateur de l'échange + by_persons: + Group activity by persons: Grouper les échanges par usager participant + Persons: Usagers participants generic_doc: filter: diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php index 7e752395c..8f75d033c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php +++ b/src/Bundle/ChillPersonBundle/Export/Helper/LabelPersonHelper.php @@ -18,6 +18,21 @@ class LabelPersonHelper { public function __construct(private readonly PersonRepository $personRepository, private readonly PersonRenderInterface $personRender) {} + public function getLabel(string $key, array $values, string $header): callable + { + return function (null|int|string $value) use ($header): string { + if ('_header' === $value) { + return $header; + } + + if ('' === $value || null === $value || null === $person = $this->personRepository->find($value)) { + return ''; + } + + return $this->personRender->renderString($person, []); + }; + } + public function getLabelMulti(string $key, array $values, string $header): callable { return function ($value) use ($header) {