From 43d9ba1ba56701c207eca52749b26092ddd8002b Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 28 Oct 2022 13:07:24 +0200 Subject: [PATCH 01/99] =?UTF-8?q?Create=2016=20new=20filters/aggregators?= =?UTF-8?q?=20in=20Bundles:=20Vend=C3=A9e,=20Person,=20Activity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basic file creation, with methods, namespace, and title translation --- .../ByActivityNumberAggregator.php | 60 +++++++++++++++++++ .../Aggregator/SentReceivedAggregator.php | 60 +++++++++++++++++++ .../Filter/ACPFilters/HasNoActivityFilter.php | 55 +++++++++++++++++ .../config/services/export.yaml | 12 ++++ .../translations/messages.fr.yml | 4 ++ .../ByActionNumberAggregator.php | 60 +++++++++++++++++++ .../CreatorJobAggregator.php | 60 +++++++++++++++++++ .../CreatorFilter.php | 55 +++++++++++++++++ .../CreatorJobFilter.php | 55 +++++++++++++++++ .../HasNoActionFilter.php | 55 +++++++++++++++++ .../HasNoReferrerFilter.php | 55 +++++++++++++++++ .../HasTemporaryLocationFilter.php | 55 +++++++++++++++++ .../services/exports_accompanying_course.yaml | 34 +++++++++++ .../translations/messages.fr.yml | 8 +++ 14 files changed, 628 insertions(+) create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php create mode 100644 src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php new file mode 100644 index 000000000..ae7492724 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group acp by activity number'; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php new file mode 100644 index 000000000..bde6e7f06 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group activity by sentreceived'; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php new file mode 100644 index 000000000..53abd2550 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter acp which has no activity'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 224075e6f..57153a193 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -120,6 +120,10 @@ services: tags: - { name: chill.export_filter, alias: 'activity_usersscope_filter' } + Chill\ActivityBundle\Export\Filter\ACPFilters\HasNoActivityFilter: + tags: + - { name: chill.export_filter, alias: 'accompanyingcourse_has_no_activity_filter' } + ## Aggregators Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator: tags: @@ -179,3 +183,11 @@ services: Chill\ActivityBundle\Export\Aggregator\ActivityUsersJobAggregator: tags: - { name: chill.export_aggregator, alias: activity_users_job_aggregator } + + Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByActivityNumberAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_by_activity_number_aggregator } + + Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator: + tags: + - { name: chill.export_aggregator, alias: activity_sentreceived_aggregator } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 6873b3736..d3ac822cb 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -276,6 +276,10 @@ Creators: Créateurs Filter activity by userscope: Filtrer les activités par service du créateur 'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%" Accepted userscope: Services + +Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activité +Group acp by activity number: Grouper les parcours par nombre d’activité +Group activity by sentreceived: Grouper les activités par envoyé / reçu #aggregators Activity type: Type d'activité diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php new file mode 100644 index 000000000..c3f94b947 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by number of actions'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php new file mode 100644 index 000000000..0eb98b0d4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by creator job'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php new file mode 100644 index 000000000..7dd78d0b4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by creator'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php new file mode 100644 index 000000000..021d2227c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by creator job'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php new file mode 100644 index 000000000..c6271b555 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by which has no action'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php new file mode 100644 index 000000000..f6ec58104 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by which has no referrer'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php new file mode 100644 index 000000000..18a6c3918 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ACP_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by temporary location'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml index 04d5d8371..71eecf4ff 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml @@ -103,6 +103,32 @@ services: tags: - { name: chill.export_filter, alias: accompanyingcourse_openbetweendates_filter } + chill.person.export.filter_has_temporary_location: + class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HasTemporaryLocationFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_has_temporary_location_filter } + + chill.person.export.filter_has_no_referrer: + class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HasNoReferrerFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_has_no_referrer_filter } + + chill.person.export.filter_has_no_action: + class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\HasNoActionFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_has_no_action_filter } + + chill.person.export.filter_creator: + class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\CreatorFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_creator_filter } + + chill.person.export.filter_creator_job: + class: Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\CreatorJobFilter + tags: + - { name: chill.export_filter, alias: accompanyingcourse_creator_job_filter } + + ## Aggregators chill.person.export.aggregator_referrer_scope: class: Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ScopeAggregator @@ -191,3 +217,11 @@ services: Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByHouseholdCompositionAggregator: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_by_household_compo_aggregator } + + Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByActionNumberAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_by_action_number_aggregator } + + Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\CreatorJobAggregator: + tags: + - { name: chill.export_aggregator, alias: accompanyingcourse_creator_job_aggregator } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index f3fd6c430..e39602dd3 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -552,6 +552,14 @@ Date from: Date de début Date to: Date de fin "Filtered by opening dates: between %datefrom% and %dateto%": "Filtrer les parcours ouverts entre deux dates: entre le %datefrom% et le %dateto%" +Filter by temporary location: Filtrer les parcours avec une localisation temporaire +Filter by which has no referrer: Filtrer les parcours sans référent +Filter by which has no action: Filtrer les parcours qui n’ont pas d’actions +Group by number of actions: Grouper les parcours par nombre d’actions +Filter by creator: Filtrer les parcours par créateur +Filter by creator job: Filtrer les parcours par métier du créateur +Group by creator job: Grouper les parcours par métier du créateur + ## social actions filters/aggr Filter by treating agent scope: Filtrer les actions par service de l'agent traitant "Filtered by treating agent scope: only %scopes%": "Filtré par service de l'agent traitant: uniquement %scopes%" From f1fb77187fc56c937d4b8230ed0a99d3038d80bf Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 28 Oct 2022 16:26:11 +0200 Subject: [PATCH 02/99] create 13 new export/filters/aggregators in Person and AsideActivity Bundles * minor corrections on last commit * modify related files (declaration, messages.fr, repository) * yaml service declaration --- .../Aggregator/SentReceivedAggregator.php | 4 +- .../Aggregator/ByActivityTypeAggregator.php | 60 ++++++++++ .../src/Export/Declarations.php | 20 ++++ .../src/Export/Export/CountAsideActivity.php | 111 ++++++++++++++++++ .../Export/Filter/ByActivityTypeFilter.php | 55 +++++++++ .../src/Export/Filter/ByDateFilter.php | 55 +++++++++ .../Repository/AsideActivityRepository.php | 48 ++------ .../src/config/services.yaml | 30 +++++ .../src/translations/messages.fr.yml | 7 ++ .../ByEndDateAggregator.php | 60 ++++++++++ .../ByMaxDateAggregator.php | 60 ++++++++++ .../ByStartDateAggregator.php | 60 ++++++++++ .../CurrentActionAggregator.php | 60 ++++++++++ .../EvaluationFilters/ByEndDateFilter.php | 55 +++++++++ .../EvaluationFilters/ByMaxDateFilter.php | 55 +++++++++ .../EvaluationFilters/ByStartDateFilter.php | 55 +++++++++ .../CurrentEvaluationsFilter.php | 55 +++++++++ .../SocialWorkFilters/CurrentActionFilter.php | 55 +++++++++ .../config/services/exports_evaluation.yaml | 44 ++++++- .../services/exports_social_actions.yaml | 4 + .../translations/messages.fr.yml | 10 ++ 21 files changed, 923 insertions(+), 40 deletions(-) create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index bde6e7f06..85c37454f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\PersonBundle\Export\Declarations; +use Chill\ActivityBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -31,7 +31,7 @@ class SentReceivedAggregator implements AggregatorInterface public function applyOn(): string { - return Declarations::ACP_TYPE; + return Declarations::ACTIVITY; } public function buildForm(FormBuilderInterface $builder) diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php new file mode 100644 index 000000000..36b643d53 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::ASIDE_ACTIVITY_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by aside activity type'; + } +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php new file mode 100644 index 000000000..0262516aa --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php @@ -0,0 +1,20 @@ +repository = $repository; + } + + public function buildForm(FormBuilderInterface $builder) + { + // TODO: Implement buildForm() method. + } + + public function getAllowedFormattersTypes(): array + { + return [FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription(): string + { + return 'Count aside activities by various parameters.'; + } + + public function getGroup(): string + { + return 'Exports of aside activities'; + } + + public function getLabels($key, array $values, $data) + { + if ('export_result' !== $key) { + throw new LogicException("the key {$key} is not used by this export"); + } + + $labels = array_combine($values, $values); + $labels['_header'] = $this->getTitle(); + + return static function ($value) use ($labels) { + return $labels[$value]; + }; + } + + public function getQueryKeys($data): array + { + return ['export_result']; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + + public function getTitle(): string + { + return 'Count aside activities'; + } + + public function getType(): string + { + return Declarations::ASIDE_ACTIVITY_TYPE; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $qb = $this->repository->createQueryBuilder('aside'); + + $qb->andWhere(); + + $qb->select('COUNT() AS export_result'); + + return $qb; + } + + public function requiredRole(): string + { + return ''; + } + + public function supportsModifiers(): array + { + return []; + } +} + + + + diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php new file mode 100644 index 000000000..60ca914b2 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ASIDE_ACTIVITY_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by aside activity type'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php new file mode 100644 index 000000000..dc6b89662 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::ASIDE_ACTIVITY_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by aside activity date'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php index f2ad9c072..b3dc46f87 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php @@ -12,46 +12,20 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Repository; use Chill\AsideActivityBundle\Entity\AsideActivity; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; -use Doctrine\Persistence\ObjectRepository; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; -final class AsideActivityRepository implements ObjectRepository +/** + * @method AsideActivity|null find($id, $lockMode = null, $lockVersion = null) + * @method AsideActivity|null findOneBy(array $criteria, array $orderBy = null) + * @method AsideActivity[] findAll() + * @method AsideActivity[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +final class AsideActivityRepository extends ServiceEntityRepository { - private EntityRepository $repository; - - public function __construct(EntityManagerInterface $entityManager) + public function __construct(ManagerRegistry $registry) { - $this->repository = $entityManager->getRepository(AsideActivity::class); - } - - public function find($id): ?AsideActivity - { - return $this->repository->find($id); - } - - /** - * @return AsideActivity[] - */ - public function findAll(): array - { - return $this->repository->findAll(); - } - - /** - * @param mixed|null $limit - * @param mixed|null $offset - * - * @return AsideActivity[] - */ - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - - public function findOneBy(array $criteria): ?AsideActivity - { - return $this->repository->findOneBy($criteria); + parent::__construct($registry, AsideActivity::class); } public function getClassName(): string diff --git a/src/Bundle/ChillAsideActivityBundle/src/config/services.yaml b/src/Bundle/ChillAsideActivityBundle/src/config/services.yaml index 34bb6da33..2a7c30d7c 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/config/services.yaml +++ b/src/Bundle/ChillAsideActivityBundle/src/config/services.yaml @@ -20,3 +20,33 @@ services: resource: "../Controller" autowire: true autoconfigure: true + + + ## Exports + + # indicators + Chill\AsideActivityBundle\Export\Export\CountAsideActivity: + autowire: true + autoconfigure: true + tags: + - { name: chill.export, alias: count_asideactivity } + + # filters + Chill\AsideActivityBundle\Export\Filter\ByDateFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: asideactivity_bydate_filter } + + Chill\AsideActivityBundle\Export\Filter\ByActivityTypeFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: asideactivity_activitytype_filter } + + # aggregators + Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: asideactivity_activitytype_aggregator } diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml index 0a7be1fcd..5b298ed68 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml @@ -166,3 +166,10 @@ Aside activities: Activités annexes Aside activity types: Types d'activités annexes Aside activity type configuration: Configuration des categories d'activités annexes Aside activity configuration: Configuration des activités annexes + +# exports +Count aside activities: Nombre d'activités annexes +Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères +Filter by aside activity date: Filtrer les activités annexes par date +Filter by aside activity type: Filtrer les activités annexes par type d'activité +Group by aside activity type: Grouper les activités annexes par type d'activité \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php new file mode 100644 index 000000000..46c3b460f --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by end date evaluations'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php new file mode 100644 index 000000000..689b6fea3 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by max date evaluations'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php new file mode 100644 index 000000000..656054250 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by start date evaluations'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php new file mode 100644 index 000000000..c69cda35d --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -0,0 +1,60 @@ +addSelect('AS _aggregator') + ->addGroupBy('_aggregator'); + } + + public function applyOn(): string + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + }; + } + + public function getQueryKeys($data): array + { + return ['_aggregator']; + } + + public function getTitle(): string + { + return 'Group by current actions'; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php new file mode 100644 index 000000000..45fddd9c1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by end date evaluations'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php new file mode 100644 index 000000000..f262a0cf4 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by max date evaluations'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php new file mode 100644 index 000000000..1d694d27c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by start date evaluations'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php new file mode 100644 index 000000000..19b7ac726 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by current evaluations'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php new file mode 100644 index 000000000..c77f9c662 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -0,0 +1,55 @@ +andWhere( + $qb->expr()->in('', ':') + ) + ->setParameter('', $data[]); + } + + public function applyOn(): string + { + return Declarations::SOCIAL_WORK_ACTION_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add(); + } + + public function describeAction($data, $format = 'string'): array + { + return ['', [ + ]]; + } + + public function getTitle(): string + { + return 'Filter by current actions'; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml index e21e0b6c1..bffde2abc 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml @@ -23,6 +23,31 @@ services: tags: - { name: chill.export_filter, alias: accompanyingcourse_maxdate_filter } + Chill\PersonBundle\Export\Filter\EvaluationFilters\ByStartDateFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: evaluation_bystartdate_filter } + + Chill\PersonBundle\Export\Filter\EvaluationFilters\ByEndDateFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: evaluation_byenddate_filter } + + Chill\PersonBundle\Export\Filter\EvaluationFilters\ByMaxDateFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: evaluation_bymaxdate_filter } + + Chill\PersonBundle\Export\Filter\EvaluationFilters\CurrentEvaluationsFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: evaluation_currentevaluations_filter } + + ## Aggregators chill.person.export.aggregator_evaluationtype: class: Chill\PersonBundle\Export\Aggregator\EvaluationAggregators\EvaluationTypeAggregator @@ -30,4 +55,21 @@ services: autoconfigure: true tags: - { name: chill.export_aggregator, alias: accompanyingcourse_evaluationtype_aggregator } - \ No newline at end of file + + Chill\PersonBundle\Export\Aggregator\EvaluationAggregators\ByStartDateAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: evaluation_bystartdate_aggregator } + + Chill\PersonBundle\Export\Aggregator\EvaluationAggregators\ByEndDateAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: evaluation_byenddate_aggregator } + + Chill\PersonBundle\Export\Aggregator\EvaluationAggregators\ByMaxDateAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: evaluation_bymaxdate_aggregator } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index 450899659..28401c3b3 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -37,6 +37,8 @@ services: tags: - { name: chill.export_filter, alias: social_work_actions_treatingagent_filter } + Chill\PersonBundle\Export\Filter\SocialWorkFilters\CurrentActionFilter: + ## AGGREGATORS chill.person.export.aggregator_action_type: class: Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\ActionTypeAggregator @@ -86,3 +88,5 @@ services: autoconfigure: true tags: - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } + + Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index e39602dd3..9243a51f8 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -559,6 +559,16 @@ Group by number of actions: Grouper les parcours par nombre d’actions Filter by creator: Filtrer les parcours par créateur Filter by creator job: Filtrer les parcours par métier du créateur Group by creator job: Grouper les parcours par métier du créateur + +Filter by current actions: Filtrer les actions en cours +Group by current actions: Grouper les actions en cours +Filter by start date evaluations: Filtrer les évaluations par date de début +Filter by end date evaluations: Filtrer les évaluations par date de fin +Filter by max date evaluations: Filtrer les évaluations par date d'échéance +Filter by current evaluations: Filtrer les évaluations en cours +Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début +Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin +Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance ## social actions filters/aggr Filter by treating agent scope: Filtrer les actions par service de l'agent traitant From fe120086c7450bea169d3f0869474f4cfd0e3914 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 28 Oct 2022 16:59:11 +0200 Subject: [PATCH 03/99] define queryKey in 11 aggregators --- .../ACPAggregators/ByActivityNumberAggregator.php | 6 +++--- .../Export/Aggregator/SentReceivedAggregator.php | 6 +++--- .../src/Export/Aggregator/ByActivityTypeAggregator.php | 6 +++--- .../ByActionNumberAggregator.php | 6 +++--- .../AccompanyingCourseAggregators/CreatorJobAggregator.php | 6 +++--- .../EvaluationAggregators/ByEndDateAggregator.php | 6 +++--- .../EvaluationAggregators/ByMaxDateAggregator.php | 6 +++--- .../EvaluationAggregators/ByStartDateAggregator.php | 6 +++--- .../SocialWorkAggregators/CurrentActionAggregator.php | 6 +++--- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php index ae7492724..44a3fd8f0 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -25,8 +25,8 @@ class ByActivityNumberAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS activity_by_number_aggregator') + ->addGroupBy('activity_by_number_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByActivityNumberAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['activity_by_number_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index 85c37454f..bf848d5e1 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -25,8 +25,8 @@ class SentReceivedAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS activity_sent_received_aggregator') + ->addGroupBy('activity_sent_received_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class SentReceivedAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['activity_sent_received_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index 36b643d53..bbbdb6284 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -25,8 +25,8 @@ class ByActivityTypeAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS aside_by_activity_type_aggregator') + ->addGroupBy('aside_by_activity_type_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByActivityTypeAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['aside_by_activity_type_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php index c3f94b947..3c16aa161 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -25,8 +25,8 @@ class ByActionNumberAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS acp_by_action_number_aggregator') + ->addGroupBy('acp_by_action_number_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByActionNumberAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['acp_by_action_number_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index 0eb98b0d4..1449091e7 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -25,8 +25,8 @@ class CreatorJobAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS acp_creator_job_aggregator') + ->addGroupBy('acp_creator_job_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class CreatorJobAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['acp_creator_job_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php index 46c3b460f..9c90c8dd3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -25,8 +25,8 @@ class ByEndDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS eval_by_end_date_aggregator') + ->addGroupBy('eval_by_end_date_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByEndDateAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['eval_by_end_date_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php index 689b6fea3..ded9fb685 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -25,8 +25,8 @@ class ByMaxDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS eval_by_max_date_aggregator') + ->addGroupBy('eval_by_max_date_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByMaxDateAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['eval_by_max_date_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index 656054250..121171d8c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -25,8 +25,8 @@ class ByStartDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS eval_by_start_date_aggregator') + ->addGroupBy('eval_by_start_date_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class ByStartDateAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['eval_by_start_date_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index c69cda35d..9a9c56afc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -25,8 +25,8 @@ class CurrentActionAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS _aggregator') - ->addGroupBy('_aggregator'); + $qb->addSelect('AS acpw_current_action_aggregator') + ->addGroupBy('acpw_current_action_aggregator'); } public function applyOn(): string @@ -50,7 +50,7 @@ class CurrentActionAggregator implements AggregatorInterface public function getQueryKeys($data): array { - return ['_aggregator']; + return ['acpw_current_action_aggregator']; } public function getTitle(): string From 8527c1907313f91d0d76a4adde1de369078518ad Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 11:18:29 +0100 Subject: [PATCH 04/99] acp HasNoAction Filter (UNTESTED) --- .../HasNoActionFilter.php | 15 +++++++-------- .../translations/messages.fr.yml | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php index c6271b555..a26628e95 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -25,11 +25,11 @@ class HasNoActionFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + if (!in_array('acpw', $qb->getAllAliases(), true)) { + $qb->join('acp.works', 'acpw'); + } + + $qb->andWhere('COUNT(acp.works) IS NULL'); } public function applyOn(): string @@ -39,13 +39,12 @@ class HasNoActionFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + // no form } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + return ['Filtered acp which has no actions']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 9243a51f8..be47a06c2 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -555,6 +555,7 @@ Date to: Date de fin Filter by temporary location: Filtrer les parcours avec une localisation temporaire Filter by which has no referrer: Filtrer les parcours sans référent Filter by which has no action: Filtrer les parcours qui n’ont pas d’actions +Filtered acp which has no actions: Filtré les parcours qui n'ont pas d'actions Group by number of actions: Grouper les parcours par nombre d’actions Filter by creator: Filtrer les parcours par créateur Filter by creator job: Filtrer les parcours par métier du créateur From a0fc9d4de5996b497c231f7d52d1b6fc6afcb0b3 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 11:43:41 +0100 Subject: [PATCH 05/99] SocialWork: Current actions filter + aggregator --- .../CurrentActionAggregator.php | 17 ++++++++++++++++- .../SocialWorkFilters/CurrentActionFilter.php | 11 +++-------- .../translations/messages.fr.yml | 3 +++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index 9a9c56afc..219aaf9cd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -25,7 +25,11 @@ class CurrentActionAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS acpw_current_action_aggregator') + $qb + ->addSelect(' + (CASE true WHEN acpw.startDate IS NULL ELSE false END) + AS acpw_current_action_aggregator + ') ->addGroupBy('acpw_current_action_aggregator'); } @@ -45,6 +49,17 @@ class CurrentActionAggregator implements AggregatorInterface if ('_header' === $value) { return ''; } + switch ($value) { + case true: + return 'Current action'; + + case false: + return 'Not current action'; + + default: + throw new \LogicException(sprintf('The value %s is not valid', $value)); + } + }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php index c77f9c662..ecbe6086a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -25,11 +25,7 @@ class CurrentActionFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + $qb->andWhere('acpw.startDate IS NULL'); } public function applyOn(): string @@ -39,13 +35,12 @@ class CurrentActionFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //no form } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + return ['Filtered by current action']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index be47a06c2..1be565938 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -562,7 +562,10 @@ Filter by creator job: Filtrer les parcours par métier du créateur Group by creator job: Grouper les parcours par métier du créateur Filter by current actions: Filtrer les actions en cours +Filtered by current action: Filtré les actions en cours Group by current actions: Grouper les actions en cours +Current action: Actions en cours +Not current action: Actions terminées Filter by start date evaluations: Filtrer les évaluations par date de début Filter by end date evaluations: Filtrer les évaluations par date de fin Filter by max date evaluations: Filtrer les évaluations par date d'échéance From 441c5c8da7b4be9a07bf8cd6100bcbbb8fc9b20d Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 14:58:25 +0100 Subject: [PATCH 06/99] remove ByMaxDateFilter (evaluation) --- .../EvaluationFilters/ByMaxDateFilter.php | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php deleted file mode 100644 index f262a0cf4..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByMaxDateFilter.php +++ /dev/null @@ -1,55 +0,0 @@ -andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); - } - - public function applyOn(): string - { - return Declarations::EVAL_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add(); - } - - public function describeAction($data, $format = 'string'): array - { - return ['', [ - ]]; - } - - public function getTitle(): string - { - return 'Filter by max date evaluations'; - } -} \ No newline at end of file From 05f9a83bed50e5e88864047b9eabd1b37dc62119 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 15:15:35 +0100 Subject: [PATCH 07/99] Evaluation HavingEndDate Aggregator --- .../HavingEndDateAggregator.php | 75 +++++++++++++++++++ .../translations/messages.fr.yml | 4 + 2 files changed, 79 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php new file mode 100644 index 000000000..8def8cf88 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php @@ -0,0 +1,75 @@ +addSelect(' + CASE true WHEN workeval.endDAte IS NULL ELSE false END + AS eval_enddate_aggregator + ') + ->addGroupBy('eval_enddate_aggregator'); + } + + public function applyOn(): string + { + return Declarations::EVAL_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + // No form needed + } + + public function getLabels($key, array $values, $data) + { + return function ($value): string { + if ('_header' === $value) { + return ''; + } + switch ($value) { + case true: + return 'enddate is specified'; + + case false: + return 'enddate is not specified'; + + default: + throw new \LogicException(sprintf('The value %s is not valid', $value)); + } + + }; + } + + public function getQueryKeys($data): array + { + return ['eval_enddate_aggregator']; + } + + public function getTitle(): string + { + return 'Group evaluations having end date'; + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 1be565938..bab2845ed 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -611,6 +611,10 @@ maxdate is specified: la date d'échéance est spécifiée maxdate is not specified: la date d'échéance n'est pas spécifiée "Filtered by maxdate: only %choice%": "Filtré par date d'échéance: uniquement si %choice%" +Group evaluations having end date: Grouper les évaluations qui ont une date de fin +enddate is specified: la date de fin est spécifiée +enddate is not specified: la date de fin n'est pas spécifiée + ## household filters/aggr Filter by composition: Filtrer les ménages par composition familiale Accepted composition: Composition familiale From d48474bbc901d9ca236acff95d424bfe2a9f17e7 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 15:32:34 +0100 Subject: [PATCH 08/99] HasNoReferrer filter --- .../HasNoReferrerFilter.php | 29 +++++++++++++++---- .../translations/messages.fr.yml | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index f6ec58104..c37d423f8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -12,9 +12,13 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Export\Declarations; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use DateTime; class HasNoReferrerFilter implements FilterInterface { @@ -26,10 +30,18 @@ class HasNoReferrerFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + ->andWhere(' + NOT EXISTS ( + SELECT 1 FROM '. UserHistory::class .' uh + WHERE uh.startDate < :date + AND ( + uh.endDate IS NULL + or uh.endDate > :date + ) + AND uh.accompanyingPeriod = acp + ) + ') + ->setParameter('date', $data['calc_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -39,12 +51,17 @@ class HasNoReferrerFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + $builder + ->add('calc_date', ChillDateType::class, [ + 'label' => 'Has no referrer on this date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ + return ['Filtered acp which has no referrer on date: %date%', [ + '%date%' => $data['calc_date']->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index bab2845ed..d2f8410ed 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -554,6 +554,8 @@ Date to: Date de fin Filter by temporary location: Filtrer les parcours avec une localisation temporaire Filter by which has no referrer: Filtrer les parcours sans référent +"Filtered acp which has no referrer on date: %date%": "Filtré les parcours sans référent à cette date: %date%" +Has no referrer on this date: N'a pas de référent à cette date Filter by which has no action: Filtrer les parcours qui n’ont pas d’actions Filtered acp which has no actions: Filtré les parcours qui n'ont pas d'actions Group by number of actions: Grouper les parcours par nombre d’actions From e3846829e18511a3bc8dd5fd0c540892bf729a0f Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 15:46:29 +0100 Subject: [PATCH 09/99] ByStartDateFilter evaluation --- .../EvaluationFilters/ByStartDateFilter.php | 24 ++++++++++++++----- .../translations/messages.fr.yml | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index 1d694d27c..afa3c212a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -12,9 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use DateTime; class ByStartDateFilter implements FilterInterface { @@ -26,10 +29,9 @@ class ByStartDateFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + ->andWhere('workeval.startDate IS BETWEEN :start_date and :end_date') + ->setParameter('start_date', $data['start_date'], Types::DATE_IMMUTABLE) + ->setParameter('end_date', $data['end_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -39,12 +41,22 @@ class ByStartDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + $builder + ->add('start_date', ChillDateType::class, [ + 'label' => 'start period date', + 'data' => new DateTime(), + ]) + ->add('end_date', ChillDateType::class, [ + 'label' => 'end period date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ + return ['Filtered by start date: between %start_date% and %end_date%', [ + '%start_date%' => $data['start_date']->format('d-m-Y'), + '%end_date%' => $data['end_date']->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index d2f8410ed..7bd0294b8 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -569,6 +569,9 @@ Group by current actions: Grouper les actions en cours Current action: Actions en cours Not current action: Actions terminées Filter by start date evaluations: Filtrer les évaluations par date de début +start period date: Date de début de la période +end period date: Date de fin de la période +"Filtered by start date: between %start_date% and %end_date%": "Filtré par la date de début: entre %start_date% et %end_date%" Filter by end date evaluations: Filtrer les évaluations par date de fin Filter by max date evaluations: Filtrer les évaluations par date d'échéance Filter by current evaluations: Filtrer les évaluations en cours From 791ea25e4f69f25f1e794bb74995df2ce27d05ea Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 15:51:35 +0100 Subject: [PATCH 10/99] ByEndDateFilter evaluation --- .../EvaluationFilters/ByEndDateFilter.php | 24 ++++++++++++++----- .../translations/messages.fr.yml | 6 ++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index 45fddd9c1..d40170447 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -12,9 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use DateTime; class ByEndDateFilter implements FilterInterface { @@ -26,10 +29,9 @@ class ByEndDateFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + ->andWhere('workeval.endDate IS BETWEEN :start_date and :end_date') + ->setParameter('start_date', $data['start_date'], Types::DATE_IMMUTABLE) + ->setParameter('end_date', $data['end_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -39,12 +41,22 @@ class ByEndDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + $builder + ->add('start_date', ChillDateType::class, [ + 'label' => 'start period date', + 'data' => new DateTime(), + ]) + ->add('end_date', ChillDateType::class, [ + 'label' => 'end period date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ + return ['Filtered by end date: between %start_date% and %end_date%', [ + '%start_date%' => $data['start_date']->format('d-m-Y'), + '%end_date%' => $data['end_date']->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 7bd0294b8..3e3ec4a2c 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -569,11 +569,11 @@ Group by current actions: Grouper les actions en cours Current action: Actions en cours Not current action: Actions terminées Filter by start date evaluations: Filtrer les évaluations par date de début +Filter by end date evaluations: Filtrer les évaluations par date de fin start period date: Date de début de la période end period date: Date de fin de la période -"Filtered by start date: between %start_date% and %end_date%": "Filtré par la date de début: entre %start_date% et %end_date%" -Filter by end date evaluations: Filtrer les évaluations par date de fin -Filter by max date evaluations: Filtrer les évaluations par date d'échéance +"Filtered by start date: between %start_date% and %end_date%": "Filtré par la date de début: comprise entre %start_date% et %end_date%" +"Filtered by end date: between %start_date% and %end_date%": "Filtré par la date de fin: comprise entre %start_date% et %end_date%" Filter by current evaluations: Filtrer les évaluations en cours Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin From 68b9c171a6afbb1d5e9eff4833ae8b905126c034 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 15:54:41 +0100 Subject: [PATCH 11/99] CurrentEvaluationsFilter --- .../EvaluationFilters/CurrentEvaluationsFilter.php | 11 +++-------- .../ChillPersonBundle/translations/messages.fr.yml | 1 + 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php index 19b7ac726..293e551f1 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -25,11 +25,7 @@ class CurrentEvaluationsFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + $qb->andWhere('workeval.endDate IS NULL'); } public function applyOn(): string @@ -39,13 +35,12 @@ class CurrentEvaluationsFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //no form needed } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + return ['Filtered by current evaluations']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 3e3ec4a2c..46cd974d3 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -575,6 +575,7 @@ end period date: Date de fin de la période "Filtered by start date: between %start_date% and %end_date%": "Filtré par la date de début: comprise entre %start_date% et %end_date%" "Filtered by end date: between %start_date% and %end_date%": "Filtré par la date de fin: comprise entre %start_date% et %end_date%" Filter by current evaluations: Filtrer les évaluations en cours +"Filtered by current evaluations": "Filtré selon les évaluations en cours" Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance From f8b5078997be88e3c8afd92d9e96cec1132ab33e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 16:10:24 +0100 Subject: [PATCH 12/99] HasNoActivityFilter (in activity) --- .../Filter/ACPFilters/HasNoActivityFilter.php | 23 +++++++++++++------ .../translations/messages.fr.yml | 1 + 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php index 53abd2550..13aaf475a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -11,10 +11,12 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Filter\ACPFilters; +use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use Doctrine\ORM\Query\Expr; class HasNoActivityFilter implements FilterInterface { @@ -25,11 +27,19 @@ class HasNoActivityFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { + if (!in_array('activity', $qb->getAllAliases(), true)) { + $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp'); + } + $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + //->andWhere('COUNT(acp.activities) IS NULL') + //TODO check this: + ->andWhere(' + NOT EXISTS ( + SELECT 1 FROM '. Activity::class .' activity + WHERE activity.accompanyingPeriod = acp + ) + '); } public function applyOn(): string @@ -39,13 +49,12 @@ class HasNoActivityFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //no form needed } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + return ['Filtered acp which has no activities']; } public function getTitle(): string diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index d3ac822cb..e3fcfd2b2 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -278,6 +278,7 @@ Filter activity by userscope: Filtrer les activités par service du créateur Accepted userscope: Services Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activité +Filtered acp which has no activities: Filtrés les parcours qui n'ont pas d'activités Group acp by activity number: Grouper les parcours par nombre d’activité Group activity by sentreceived: Grouper les activités par envoyé / reçu From ed04c276c23de6817e6960bd9337bfce8bce8485 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 31 Oct 2022 16:18:10 +0100 Subject: [PATCH 13/99] SentReceivedAggregator (in activity) --- .../Export/Aggregator/SentReceivedAggregator.php | 16 +++++++++++++--- .../CurrentActionAggregator.php | 1 - 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index bf848d5e1..b5300834c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -25,8 +25,8 @@ class SentReceivedAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS activity_sent_received_aggregator') - ->addGroupBy('activity_sent_received_aggregator'); + $qb->addSelect('activity.sentReceived AS activity_sentreceived_aggregator') + ->addGroupBy('activity_sentreceived_aggregator'); } public function applyOn(): string @@ -45,12 +45,22 @@ class SentReceivedAggregator implements AggregatorInterface if ('_header' === $value) { return ''; } + switch ($value) { + case 'sent': + return 'is sent'; + + case 'received': + return 'is received'; + + default: + throw new \LogicException(sprintf('The value %s is not valid', $value)); + } }; } public function getQueryKeys($data): array { - return ['activity_sent_received_aggregator']; + return ['activity_sentreceived_aggregator']; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index 219aaf9cd..d9120d121 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -59,7 +59,6 @@ class CurrentActionAggregator implements AggregatorInterface default: throw new \LogicException(sprintf('The value %s is not valid', $value)); } - }; } From 7dc34cb3572542f82de57c9d7027f447cd05f572 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 10:15:08 +0100 Subject: [PATCH 14/99] correct config file --- .../ChillPersonBundle/config/services/exports_evaluation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml index bffde2abc..a389c1f80 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml @@ -35,7 +35,7 @@ services: tags: - { name: chill.export_filter, alias: evaluation_byenddate_filter } - Chill\PersonBundle\Export\Filter\EvaluationFilters\ByMaxDateFilter: + Chill\PersonBundle\Export\Filter\EvaluationFilters\MaxDateFilter: autowire: true autoconfigure: true tags: From dc149c7fd5b681f7a4bf61ed5c3964f447a341ce Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 10:26:44 +0100 Subject: [PATCH 15/99] correct namespace and use statements --- .../src/Export/Aggregator/ByActivityTypeAggregator.php | 2 +- src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php | 2 +- .../src/Export/Export/CountAsideActivity.php | 2 +- .../src/Export/Filter/ByActivityTypeFilter.php | 2 +- .../ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index bbbdb6284..d15d107aa 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; -use ChillAsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php index 0262516aa..7ddbec6de 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php @@ -9,7 +9,7 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -namespace ChillAsideActivityBundle\Export; +namespace Chill\AsideActivityBundle\Export; /** * This class declare constants used for the export framework. diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index 7af39568e..d6c391121 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -15,7 +15,7 @@ use Chill\AsideActivityBundle\Repository\AsideActivityRepository; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; -use ChillAsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Export\Declarations; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\Query; use LogicException; diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 60ca914b2..53bd904fa 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use ChillAsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index dc6b89662..dbab304d2 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use ChillAsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; From 1228a0323ce54bf051d4a0da89d9511ecc95c563 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 10:28:52 +0100 Subject: [PATCH 16/99] php csfixes --- .../ACPAggregators/ByActivityNumberAggregator.php | 4 ++-- .../Export/Aggregator/SentReceivedAggregator.php | 10 ++++++---- .../Export/Filter/ACPFilters/HasNoActivityFilter.php | 7 ++++--- .../Export/Filter/UsersJobFilter.php | 4 ++-- .../Export/Aggregator/ByActivityTypeAggregator.php | 6 +++--- .../src/Export/Declarations.php | 2 +- .../src/Export/Export/CountAsideActivity.php | 8 ++------ .../src/Export/Filter/ByActivityTypeFilter.php | 4 ++-- .../src/Export/Filter/ByDateFilter.php | 4 ++-- .../ByActionNumberAggregator.php | 4 ++-- .../ByHouseholdCompositionAggregator.php | 3 ++- .../CreatorJobAggregator.php | 4 ++-- .../EvaluationAggregators/ByEndDateAggregator.php | 4 ++-- .../EvaluationAggregators/ByMaxDateAggregator.php | 4 ++-- .../EvaluationAggregators/ByStartDateAggregator.php | 4 ++-- .../HavingEndDateAggregator.php | 9 +++++---- .../CurrentActionAggregator.php | 10 ++++++---- .../AccompanyingCourseFilters/CreatorFilter.php | 2 +- .../AccompanyingCourseFilters/CreatorJobFilter.php | 2 +- .../AccompanyingCourseFilters/HasNoActionFilter.php | 3 ++- .../HasNoReferrerFilter.php | 12 ++++++------ .../HasTemporaryLocationFilter.php | 2 +- .../Filter/EvaluationFilters/ByEndDateFilter.php | 4 ++-- .../Filter/EvaluationFilters/ByStartDateFilter.php | 4 ++-- .../EvaluationFilters/CurrentEvaluationsFilter.php | 2 +- .../Filter/SocialWorkFilters/CurrentActionFilter.php | 2 +- 26 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php index 44a3fd8f0..de35f75cc 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByActivityNumberAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index b5300834c..2a6dec7f7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -11,9 +11,10 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; -use Chill\MainBundle\Export\AggregatorInterface; use Chill\ActivityBundle\Export\Declarations; +use Chill\MainBundle\Export\AggregatorInterface; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class SentReceivedAggregator implements AggregatorInterface @@ -41,10 +42,11 @@ class SentReceivedAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case 'sent': return 'is sent'; @@ -53,7 +55,7 @@ class SentReceivedAggregator implements AggregatorInterface return 'is received'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } }; } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php index 13aaf475a..508644a07 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -14,9 +14,10 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\Query\Expr; +use function in_array; class HasNoActivityFilter implements FilterInterface { @@ -36,7 +37,7 @@ class HasNoActivityFilter implements FilterInterface //TODO check this: ->andWhere(' NOT EXISTS ( - SELECT 1 FROM '. Activity::class .' activity + SELECT 1 FROM ' . Activity::class . ' activity WHERE activity.accompanyingPeriod = acp ) '); @@ -61,4 +62,4 @@ class HasNoActivityFilter implements FilterInterface { return 'Filter acp which has no activity'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php index dcdacd84a..b52ef441c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php @@ -39,9 +39,9 @@ class UsersJobFilter implements FilterInterface $qb ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . Activity::class . ' activity_users_job_filter_act + 'SELECT 1 FROM ' . Activity::class . ' activity_users_job_filter_act JOIN activity_users_job_filter_act.users users WHERE users.userJob IN (:activity_users_job_filter_jobs) AND activity_users_job_filter_act = activity ' - ) + ) ) ->setParameter('activity_users_job_filter_jobs', $data['jobs']); } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index d15d107aa..488885bde 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -11,8 +11,8 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Aggregator; -use Chill\MainBundle\Export\AggregatorInterface; use Chill\AsideActivityBundle\Export\Declarations; +use Chill\MainBundle\Export\AggregatorInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -41,7 +41,7 @@ class ByActivityTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php index 7ddbec6de..8c808ea37 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php @@ -17,4 +17,4 @@ namespace Chill\AsideActivityBundle\Export; abstract class Declarations { public const ASIDE_ACTIVITY_TYPE = 'aside_activity'; -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index d6c391121..d1d69f0c8 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -11,14 +11,14 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Export; +use Chill\AsideActivityBundle\Export\Declarations; use Chill\AsideActivityBundle\Repository\AsideActivityRepository; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; -use Chill\AsideActivityBundle\Export\Declarations; -use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\Query; use LogicException; +use Symfony\Component\Form\FormBuilderInterface; class CountAsideActivity implements ExportInterface, GroupedExportInterface { @@ -105,7 +105,3 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface return []; } } - - - - diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 53bd904fa..4f256538d 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -11,8 +11,8 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Filter; -use Chill\MainBundle\Export\FilterInterface; use Chill\AsideActivityBundle\Export\Declarations; +use Chill\MainBundle\Export\FilterInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -52,4 +52,4 @@ class ByActivityTypeFilter implements FilterInterface { return 'Filter by aside activity type'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index dbab304d2..d8fec664a 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -11,8 +11,8 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Filter; -use Chill\MainBundle\Export\FilterInterface; use Chill\AsideActivityBundle\Export\Declarations; +use Chill\MainBundle\Export\FilterInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -52,4 +52,4 @@ class ByDateFilter implements FilterInterface { return 'Filter by aside activity date'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php index 3c16aa161..0f51b6feb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByActionNumberAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php index e96c8a228..f299762e6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php @@ -18,6 +18,7 @@ use Chill\PersonBundle\Entity\Household\HouseholdComposition; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface; +use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -96,7 +97,7 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface $builder->add('date_calc', ChillDateType::class, [ 'label' => 'export.aggregator.course.by_household_composition.Calc date', 'input_format' => 'datetime_immutable', - 'data' => new \DateTimeImmutable('now'), + 'data' => new DateTimeImmutable('now'), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index 1449091e7..c473bf7a1 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class CreatorJobAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php index 9c90c8dd3..40b035a02 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByEndDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php index ded9fb685..36ab0f50b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByMaxDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index 121171d8c..e64245d53 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByStartDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php index 8def8cf88..af801b74d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Aggregator\EvaluationAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class HavingEndDateAggregator implements AggregatorInterface @@ -45,10 +46,11 @@ class HavingEndDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case true: return 'enddate is specified'; @@ -57,9 +59,8 @@ class HavingEndDateAggregator implements AggregatorInterface return 'enddate is not specified'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } - }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index d9120d121..a77838167 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class CurrentActionAggregator implements AggregatorInterface @@ -27,7 +28,7 @@ class CurrentActionAggregator implements AggregatorInterface { $qb ->addSelect(' - (CASE true WHEN acpw.startDate IS NULL ELSE false END) + (CASE true WHEN acpw.startDate IS NULL ELSE false END) AS acpw_current_action_aggregator ') ->addGroupBy('acpw_current_action_aggregator'); @@ -45,10 +46,11 @@ class CurrentActionAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case true: return 'Current action'; @@ -57,7 +59,7 @@ class CurrentActionAggregator implements AggregatorInterface return 'Not current action'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php index 7dd78d0b4..c7e110f62 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -52,4 +52,4 @@ class CreatorFilter implements FilterInterface { return 'Filter by creator'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index 021d2227c..6f094fe97 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -52,4 +52,4 @@ class CreatorJobFilter implements FilterInterface { return 'Filter by creator job'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php index a26628e95..771b8d063 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use function in_array; class HasNoActionFilter implements FilterInterface { @@ -51,4 +52,4 @@ class HasNoActionFilter implements FilterInterface { return 'Filter by which has no action'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index c37d423f8..b18bcd1de 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -15,10 +15,10 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class HasNoReferrerFilter implements FilterInterface { @@ -32,12 +32,12 @@ class HasNoReferrerFilter implements FilterInterface $qb ->andWhere(' NOT EXISTS ( - SELECT 1 FROM '. UserHistory::class .' uh - WHERE uh.startDate < :date + SELECT 1 FROM ' . UserHistory::class . ' uh + WHERE uh.startDate < :date AND ( - uh.endDate IS NULL + uh.endDate IS NULL or uh.endDate > :date - ) + ) AND uh.accompanyingPeriod = acp ) ') @@ -69,4 +69,4 @@ class HasNoReferrerFilter implements FilterInterface { return 'Filter by which has no referrer'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 18a6c3918..85d8d93b6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -52,4 +52,4 @@ class HasTemporaryLocationFilter implements FilterInterface { return 'Filter by temporary location'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index d40170447..5c509d50c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -14,10 +14,10 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class ByEndDateFilter implements FilterInterface { @@ -64,4 +64,4 @@ class ByEndDateFilter implements FilterInterface { return 'Filter by end date evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index afa3c212a..e21a1ea68 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -14,10 +14,10 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class ByStartDateFilter implements FilterInterface { @@ -64,4 +64,4 @@ class ByStartDateFilter implements FilterInterface { return 'Filter by start date evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php index 293e551f1..50c95600e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -47,4 +47,4 @@ class CurrentEvaluationsFilter implements FilterInterface { return 'Filter by current evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php index ecbe6086a..cbf958182 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -47,4 +47,4 @@ class CurrentActionFilter implements FilterInterface { return 'Filter by current actions'; } -} \ No newline at end of file +} From 4af261a36631058588ed1f43687143165c15d6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 25 Oct 2022 09:25:30 +0200 Subject: [PATCH 17/99] Fixed: correctly show datetime in spreadsheet list --- .../Formatter/SpreadsheetListFormatter.php | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php index ab9c2e893..0e5e339ea 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php @@ -20,11 +20,12 @@ use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use RuntimeException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\Response; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; use function array_key_exists; use function array_keys; use function array_map; @@ -80,7 +81,7 @@ class SpreadsheetListFormatter implements FormatterInterface * * @uses appendAggregatorForm * - * @param type $exportAlias + * @param string $exportAlias */ public function buildForm( FormBuilderInterface $builder, @@ -144,8 +145,6 @@ class SpreadsheetListFormatter implements FormatterInterface $i = 1; foreach ($result as $row) { - $line = []; - if (true === $this->formatterData['numerotation']) { $worksheet->setCellValue('A' . ($i + 1), (string) $i); } @@ -155,13 +154,22 @@ class SpreadsheetListFormatter implements FormatterInterface foreach ($row as $key => $value) { $row = $a . ($i + 1); - if ($value instanceof DateTimeInterface) { - $worksheet->setCellValue($row, Date::PHPToExcel($value)); - $worksheet->getStyle($row) - ->getNumberFormat() - ->setFormatCode(NumberFormat::FORMAT_DATE_DDMMYYYY); + $formattedValue = $this->getLabel($key, $value); + + if ($formattedValue instanceof DateTimeInterface) { + $worksheet->setCellValue($row, Date::PHPToExcel($formattedValue)); + + if ($formattedValue->format('His') === '000000') { + $worksheet->getStyle($row) + ->getNumberFormat() + ->setFormatCode(NumberFormat::FORMAT_DATE_DDMMYYYY); + } else { + $worksheet->getStyle($row) + ->getNumberFormat() + ->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME); + } } else { - $worksheet->setCellValue($row, $this->getLabel($key, $value)); + $worksheet->setCellValue($row, $formattedValue); } ++$a; } @@ -259,6 +267,10 @@ class SpreadsheetListFormatter implements FormatterInterface foreach ($keys as $key) { // get an array with all values for this key if possible $values = array_map(static function ($v) use ($key) { + if (!array_key_exists($key, $v)) { + throw new RuntimeException(sprintf('This key does not exists: %s. Available keys are %s', $key, implode(', ', array_keys($v)))); + } + return $v[$key]; }, $this->result); // store the label in the labelsCache property From 333c305eef548fe0fc4270f1098f9c1fc8a9a977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 25 Oct 2022 10:23:02 +0200 Subject: [PATCH 18/99] Fixed: [export][list person] use address from household for person list --- exports_alias_conventions.md | 133 +++++----- .../Export/Helper/ExportAddressHelper.php | 247 ++++++++++++++++++ .../config/services/export.yaml | 3 + .../translations/messages.fr.yml | 167 ++++++------ .../ChillPersonBundle/Entity/Person.php | 2 +- .../Export/Export/ListPerson.php | 200 +++++++------- 6 files changed, 515 insertions(+), 237 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php diff --git a/exports_alias_conventions.md b/exports_alias_conventions.md index 62fc745d8..fd7844691 100644 --- a/exports_alias_conventions.md +++ b/exports_alias_conventions.md @@ -5,69 +5,70 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt These are alias conventions : -| Entity | Join | Attribute | Alias | -|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:----------------------------------| -| AccompanyingPeriod::class | | | acp | -| | AccompanyingPeriodWork::class | acp.works | acpw | -| | AccompanyingPeriodParticipation::class | acp.participations | acppart | -| | Location::class | acp.administrativeLocation | acploc | -| | ClosingMotive::class | acp.closingMotive | acpmotive | -| | UserJob::class | acp.job | acpjob | -| | Origin::class | acp.origin | acporigin | -| | Scope::class | acp.scopes | acpscope | -| | SocialIssue::class | acp.socialIssues | acpsocialissue | -| | User::class | acp.user | acpuser | -| | AccompanyingPeriopStepHistory::class | acp.stepHistories | acpstephistories | -| AccompanyingPeriodWork::class | | | acpw | -| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval | -| | User::class | acpw.referrers | acpwuser | -| | SocialAction::class | acpw.socialAction | acpwsocialaction | -| | Goal::class | acpw.goals | goal | -| | Result::class | acpw.results | result | -| AccompanyingPeriodParticipation::class | | | acppart | -| | Person::class | acppart.person | partperson | -| AccompanyingPeriodWorkEvaluation::class | | | workeval | -| | Evaluation::class | workeval.evaluation | eval | -| Goal::class | | | goal | -| | Result::class | goal.results | goalresult | -| Person::class | | | person | -| | Center::class | person.center | center | -| | HouseholdMember::class | partperson.householdParticipations | householdmember | -| | MaritalStatus::class | person.maritalStatus | personmarital | -| | VendeePerson::class | | vp | -| | VendeePersonMineur::class | | vpm | -| ResidentialAddress::class | | | resaddr | -| | ThirdParty::class | resaddr.hostThirdParty | tparty | -| ThirdParty::class | | | tparty | -| | ThirdPartyCategory::class | tparty.categories | tpartycat | -| HouseholdMember::class | | | householdmember | -| | Household::class | householdmember.household | household | -| | Person::class | householdmember.person | memberperson | -| | | memberperson.center | membercenter | -| Household::class | | | household | -| | HouseholdComposition::class | household.compositions | composition | -| Activity::class | | | activity | -| | Person::class | activity.person | actperson | -| | AccompanyingPeriod::class | activity.accompanyingPeriod | acp | -| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity | -| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity | -| | ActivityType::class | activity.activityType | acttype | -| | Location::class | activity.location | actloc | -| | SocialAction::class | activity.socialActions | actsocialaction | -| | SocialIssue::class | activity.socialIssues | actsocialssue | -| | ThirdParty::class | activity.thirdParties | acttparty | -| | User::class | activity.user | actuser | -| | User::class | activity.users | actusers | -| | ActivityReason::class | activity.reasons | actreasons | -| | Center::class | actperson.center | actcenter | -| | Person::class | activity.createdBy | actcreator | -| ActivityReason::class | | | actreasons | -| | ActivityReasonCategory::class | actreason.category | actreasoncat | -| Calendar::class | | | cal | -| | CancelReason::class | cal.cancelReason | calcancel | -| | Location::class | cal.location | calloc | -| | User::class | cal.user | caluser | -| VendeePerson::class | | | vp | -| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof | -| | StatutLogement::class | vp.statutLogement | vplog | -| | TempsDeTravail::class | vp.tempsDeTravail | vptt | +| Entity | Join | Attribute | Alias | +|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:---------------------------------------| +| AccompanyingPeriod::class | | | acp | +| | AccompanyingPeriodWork::class | acp.works | acpw | +| | AccompanyingPeriodParticipation::class | acp.participations | acppart | +| | Location::class | acp.administrativeLocation | acploc | +| | ClosingMotive::class | acp.closingMotive | acpmotive | +| | UserJob::class | acp.job | acpjob | +| | Origin::class | acp.origin | acporigin | +| | Scope::class | acp.scopes | acpscope | +| | SocialIssue::class | acp.socialIssues | acpsocialissue | +| | User::class | acp.user | acpuser | +| | AccompanyingPeriopStepHistory::class | acp.stepHistories | acpstephistories | +| AccompanyingPeriodWork::class | | | acpw | +| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval | +| | User::class | acpw.referrers | acpwuser | +| | SocialAction::class | acpw.socialAction | acpwsocialaction | +| | Goal::class | acpw.goals | goal | +| | Result::class | acpw.results | result | +| AccompanyingPeriodParticipation::class | | | acppart | +| | Person::class | acppart.person | partperson | +| AccompanyingPeriodWorkEvaluation::class | | | workeval | +| | Evaluation::class | workeval.evaluation | eval | +| Goal::class | | | goal | +| | Result::class | goal.results | goalresult | +| Person::class | | | person | +| | Center::class | person.center | center | +| | HouseholdMember::class | partperson.householdParticipations | householdmember | +| | MaritalStatus::class | person.maritalStatus | personmarital | +| | VendeePerson::class | | vp | +| | VendeePersonMineur::class | | vpm | +| | CurrentPersonAddress::class | person.currentPersonAddress | currentPersonAddress (on a given date) | +| ResidentialAddress::class | | | resaddr | +| | ThirdParty::class | resaddr.hostThirdParty | tparty | +| ThirdParty::class | | | tparty | +| | ThirdPartyCategory::class | tparty.categories | tpartycat | +| HouseholdMember::class | | | householdmember | +| | Household::class | householdmember.household | household | +| | Person::class | householdmember.person | memberperson | +| | | memberperson.center | membercenter | +| Household::class | | | household | +| | HouseholdComposition::class | household.compositions | composition | +| Activity::class | | | activity | +| | Person::class | activity.person | actperson | +| | AccompanyingPeriod::class | activity.accompanyingPeriod | acp | +| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity | +| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity | +| | ActivityType::class | activity.activityType | acttype | +| | Location::class | activity.location | actloc | +| | SocialAction::class | activity.socialActions | actsocialaction | +| | SocialIssue::class | activity.socialIssues | actsocialssue | +| | ThirdParty::class | activity.thirdParties | acttparty | +| | User::class | activity.user | actuser | +| | User::class | activity.users | actusers | +| | ActivityReason::class | activity.reasons | actreasons | +| | Center::class | actperson.center | actcenter | +| | Person::class | activity.createdBy | actcreator | +| ActivityReason::class | | | actreasons | +| | ActivityReasonCategory::class | actreason.category | actreasoncat | +| Calendar::class | | | cal | +| | CancelReason::class | cal.cancelReason | calcancel | +| | Location::class | cal.location | calloc | +| | User::class | cal.user | caluser | +| VendeePerson::class | | | vp | +| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof | +| | StatutLogement::class | vp.statutLogement | vplog | +| | TempsDeTravail::class | vp.tempsDeTravail | vptt | diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php new file mode 100644 index 000000000..09aaa7a1d --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -0,0 +1,247 @@ + self::COUNTRY, + 'postal_code' => self::POSTAL_CODE, + 'street' => self::STREET, + 'building' => self::BUILDING, + 'string' => self::STRING, + 'geom' => self::GEOM, + 'attributes' => self::ATTRIBUTES, + ]; + + private const COLUMN_MAPPING = [ + 'country' => ['country'], + 'postal_code' => ['postcode_code', 'postcode_name'], + 'street' => ['street', 'streetNumber'], + 'building' => ['buildingName', 'corridor', 'distribution', 'extra', 'flat', 'floor'], + 'string' => ['_as_string'], + 'attributes' => ['isNoAddress', 'confidential', 'id'], + 'geom' => ['_lat', '_lon'], + ]; + + private AddressRender $addressRender; + + private AddressRepository $addressRepository; + + private PropertyAccessor $propertyAccess; + + private TranslatableStringHelperInterface $translatableStringHelper; + + public function __construct( + AddressRepository $addressRepository, + TranslatableStringHelperInterface $translatableStringHelper, + AddressRender $addressRender + ) { + $this->addressRepository = $addressRepository; + $this->propertyAccess = PropertyAccess::createPropertyAccessor(); + $this->translatableStringHelper = $translatableStringHelper; + $this->addressRender = $addressRender; + } + + /** + * @return array|string[] + */ + public function getKeys(int $params, string $prefix = ''): array + { + $prefixes = []; + + foreach (self::ALL as $key => $bitmask) { + if (($params & $bitmask) === $bitmask) { + $prefixes = array_merge( + $prefixes, + array_map( + static function ($item) use ($prefix) { return $prefix . $item; }, + self::COLUMN_MAPPING[$key] + ) + ); + } + } + + return $prefixes; + } + + public function getLabel($key, array $values, $data, string $prefix = '', string $translationPrefix = 'export.address_helper.'): callable + { + $sanitizedKey = substr($key, strlen($prefix)); + + switch ($sanitizedKey) { + case 'id': + case 'street': + case 'streetNumber': + case 'buildingName': + case 'corridor': + case 'distribution': + case 'extra': + case 'flat': + case 'floor': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + + return $this->propertyAccess->getValue($address, $sanitizedKey); + }; + + case '_lat': + case '_lon': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + $geom = $address->getPoint(); + + if (null === $geom) { + return ''; + } + + switch ($sanitizedKey) { + case '_lat': + return $geom->getLat(); + + case '_lon': + return $geom->getLon(); + + default: + throw new LogicException('only _lat or _lon accepted, given: ' . $sanitizedKey); + } + }; + + case 'isNoAddress': + case 'confidential': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + + switch ($val = $this->propertyAccess->getValue($address, $sanitizedKey)) { + case null: + return ''; + + case true: + return 1; + + case false: + return 0; + + default: + throw new LogicException('this value is not supported for ' . $sanitizedKey . ': ' . $val); + } + }; + + case 'country': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + + return $this->translatableStringHelper->localize($address->getPostcode()->getCountry()->getName()); + }; + + case '_as_string': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + + return $this->addressRender->renderString($address, []); + }; + + case 'postcode_code': + case 'postcode_name': + return function ($value) use ($sanitizedKey, $translationPrefix) { + if ('_header' === $value) { + return $translationPrefix . $sanitizedKey; + } + + if (null === $value) { + return ''; + } + + $address = $this->addressRepository->find($value); + + switch ($sanitizedKey) { + case 'postcode_code': + return $address->getPostcode()->getCode(); + + case 'postcode_name': + return $address->getPostcode()->getName(); + + default: + throw new LogicException('this key is not supported: ' . $sanitizedKey); + } + }; + + default: + throw new LogicException('this key is not supported: ' . $sanitizedKey); + } + } +} diff --git a/src/Bundle/ChillMainBundle/config/services/export.yaml b/src/Bundle/ChillMainBundle/config/services/export.yaml index d330f30f5..ea7328839 100644 --- a/src/Bundle/ChillMainBundle/config/services/export.yaml +++ b/src/Bundle/ChillMainBundle/config/services/export.yaml @@ -3,6 +3,9 @@ services: autowire: true autoconfigure: true + Chill\MainBundle\Export\Helper\: + resource: '../../Export/Helper' + chill.main.export_element_validator: class: Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraintValidator tags: diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index b4ce910c4..01fcf0b8c 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -79,17 +79,17 @@ Postal code: Code postal Valid from: Valide à partir du Choose a postal code: Choisir un code postal address: - address_homeless: L'adresse est-elle celle d'un domicile fixe ? - real address: Adresse d'un domicile - consider homeless: Cette adresse est incomplète + address_homeless: L'adresse est-elle celle d'un domicile fixe ? + real address: Adresse d'un domicile + consider homeless: Cette adresse est incomplète address more: - floor: ét - corridor: coul - steps: esc - flat: appart - buildingName: résidence - extra: "" - distribution: cedex + floor: ét + corridor: coul + steps: esc + flat: appart + buildingName: résidence + extra: "" + distribution: cedex Create a new address: Créer une nouvelle adresse Create an address: Créer une adresse Update address: Modifier l'adresse @@ -125,7 +125,7 @@ Location and location type: Localisations et types de localisation Back to the admin: Menu d'administration "Administration interface": Interface d'administration Welcome to the admin section !: > - Bienvenue dans l'interface d'administration ! + Bienvenue dans l'interface d'administration ! #permissions Permissions Menu: Gestion des droits @@ -334,69 +334,69 @@ Impersonate: Incarner l'utilisateur Impersonate mode: Mode fantôme crud: - # general items - new: - button_action_form: Créer - link_edit: Modifier - save_and_close: Créer & fermer - save_and_show: Créer & voir - save_and_new: Créer & nouveau - success: Les données ont été créées - edit: - button_action_form: Enregistrer - back_to_view: Voir - save_and_close: Enregistrer & fermer - save_and_show: Enregistrer & voir - success: Les données ont été modifiées - delete: - success: Les données ont été supprimées - link_to_form: Supprimer - default: - success: Les données ont été enregistrées - view: - link_duplicate: Dupliquer - admin_user: - index: - title: Utilisateurs - add_new: Créer - title_edit: Modifier un utilisateur - title_new: Créer un utilisateur - admin_user_job: - index: - title: Métiers - add_new: Créer - title_new: Nouveau métier - title_edit: Modifier un métier - main_location_type: - index: - title: Liste des types de localisations - add_new: Ajouter un type de localisation - title_new: Nouveau type de localisation - title_edit: Modifier un type de localisation - main_location: - index: - title: Liste des localisations - add_new: Ajouter une localisation - title_new: Nouvelle localisation - title_edit: Modifier une localisation - main_language: - index: - title: Liste des langues - add_new: Ajouter une langue - title_new: Nouvelle langue - title_edit: Modifier une langue - main_country: - index: - title: Liste des pays - add_new: Ajouter un pays - title_new: Nouveau pays - title_edit: Modifier un pays - main_civility: - index: - title: Liste des civilités - add_new: Ajouter une civilité - title_new: Nouvelle civilité - title_edit: Modifier une civilité + # general items + new: + button_action_form: Créer + link_edit: Modifier + save_and_close: Créer & fermer + save_and_show: Créer & voir + save_and_new: Créer & nouveau + success: Les données ont été créées + edit: + button_action_form: Enregistrer + back_to_view: Voir + save_and_close: Enregistrer & fermer + save_and_show: Enregistrer & voir + success: Les données ont été modifiées + delete: + success: Les données ont été supprimées + link_to_form: Supprimer + default: + success: Les données ont été enregistrées + view: + link_duplicate: Dupliquer + admin_user: + index: + title: Utilisateurs + add_new: Créer + title_edit: Modifier un utilisateur + title_new: Créer un utilisateur + admin_user_job: + index: + title: Métiers + add_new: Créer + title_new: Nouveau métier + title_edit: Modifier un métier + main_location_type: + index: + title: Liste des types de localisations + add_new: Ajouter un type de localisation + title_new: Nouveau type de localisation + title_edit: Modifier un type de localisation + main_location: + index: + title: Liste des localisations + add_new: Ajouter une localisation + title_new: Nouvelle localisation + title_edit: Modifier une localisation + main_language: + index: + title: Liste des langues + add_new: Ajouter une langue + title_new: Nouvelle langue + title_edit: Modifier une langue + main_country: + index: + title: Liste des pays + add_new: Ajouter un pays + title_new: Nouveau pays + title_edit: Modifier un pays + main_civility: + index: + title: Liste des civilités + add_new: Ajouter une civilité + title_new: Nouvelle civilité + title_edit: Modifier une civilité No entities: Aucun élément @@ -515,3 +515,22 @@ notification: Remove an email: Supprimer l'adresse email Email with access link: Adresse email ayant reçu un lien d'accès +export: + address_helper: + id: Identifiant de l'adresse + street: Voie + streetNumber: Numéro de voie + buildingName: Résidence + corridor: Couloir + distribution: Distribution + extra: Extra + flat: Appartement + floor: Étage + postcode_code: Code postal + postcode_name: Libellé du code postal + country: Pays + _as_string: Adresse formattée + confidential: Adresse confidentielle ? + isNoAddress: Adresse incomplète ? + _lat: Latitude + _lon: Longitude diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 0d6e3e493..48864120d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -1760,7 +1760,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI } /** - * @param type $spokenLanguages + * @param Collection $spokenLanguages */ public function setSpokenLanguages($spokenLanguages): self { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 5f5d95034..e799a53e4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -17,28 +17,33 @@ use Chill\CustomFieldsBundle\Service\CustomFieldProvider; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; +use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\ListInterface; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Repository\CountryRepository; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\PersonVoter; use DateTime; +use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; use Exception; +use PhpOffice\PhpSpreadsheet\Shared\Date; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; use function addcslashes; use function array_key_exists; use function array_keys; use function array_merge; use function count; use function in_array; +use function strlen; use function strtolower; use function uniqid; @@ -47,31 +52,40 @@ use function uniqid; */ class ListPerson implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface { - protected CustomFieldProvider $customFieldProvider; - - protected EntityManagerInterface $entityManager; - - protected array $fields = [ - 'id', 'firstName', 'lastName', 'birthdate', + public const FIELDS = [ + 'id', + 'firstName', + 'lastName', + 'birthdate', 'placeOfBirth', 'gender', 'memo', 'email', 'phonenumber', 'mobilenumber', 'contactInfo', 'countryOfBirth', 'nationality', - 'address_street_address_1', 'address_street_address_2', - 'address_valid_from', 'address_postcode_label', 'address_postcode_code', - 'address_country_name', 'address_country_code', 'address_isnoaddress', + 'address', ]; - protected TranslatableStringHelper $translatableStringHelper; + private ExportAddressHelper $addressHelper; - protected TranslatorInterface $translator; + private CountryRepository $countryRepository; + + private CustomFieldProvider $customFieldProvider; + + private EntityManagerInterface $entityManager; private $slugs = []; + private TranslatableStringHelper $translatableStringHelper; + + private TranslatorInterface $translator; + public function __construct( + CountryRepository $countryRepository, + ExportAddressHelper $addressHelper, EntityManagerInterface $em, TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, CustomFieldProvider $customFieldProvider ) { + $this->addressHelper = $addressHelper; + $this->countryRepository = $countryRepository; $this->entityManager = $em; $this->translator = $translator; $this->translatableStringHelper = $translatableStringHelper; @@ -80,7 +94,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou public function buildForm(FormBuilderInterface $builder) { - $choices = array_combine($this->fields, $this->fields); + $choices = array_combine(self::FIELDS, self::FIELDS); foreach ($this->getCustomFields() as $cf) { $choices[$this->translatableStringHelper->localize($cf->getName())] @@ -96,7 +110,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou 'label' => 'Fields to include in export', 'choice_attr' => static function (string $val): array { // add a 'data-display-target' for address fields - if (substr($val, 0, 8) === 'address_') { + if (substr($val, 0, 7) === 'address') { return ['data-display-target' => 'address_date']; } @@ -111,17 +125,14 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } }, ])], + 'data' => array_values($choices), ]); // add a date field for addresses - $builder->add('address_date', DateType::class, [ + $builder->add('address_date', ChillDateType::class, [ 'label' => 'Address valid at this date', - 'data' => new DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy', - 'required' => false, - 'block_name' => 'list_export_form_address_date', + 'data' => new DateTimeImmutable(), + 'input' => 'datetime_immutable', ]); } @@ -142,6 +153,10 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou public function getLabels($key, array $values, $data) { + if (substr($key, 0, strlen('address')) === 'address') { + return $this->addressHelper->getLabel($key, $values, $data, 'address_'); + } + switch ($key) { case 'birthdate': // for birthdate, we have to transform the string into a date @@ -151,10 +166,11 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou return 'birthdate'; } - if (empty($value)) { + if (null === $value) { return ''; } + // warning: won't work with DateTimeImmutable as we reset time a few lines later $date = DateTime::createFromFormat('Y-m-d', $value); // check that the creation could occurs. if (false === $date) { @@ -162,7 +178,9 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou . 'not be converted to %s', $value, DateTime::class)); } - return $date->format('d-m-Y'); + $date->setTime(0, 0, 0); + + return $date; }; case 'gender': @@ -177,29 +195,6 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou case 'countryOfBirth': case 'nationality': - $countryRepository = $this->entityManager - ->getRepository(\Chill\MainBundle\Entity\Country::class); - - // load all countries in a single query - $countryRepository->findBy(['countryCode' => $values]); - - return function ($value) use ($key, $countryRepository) { - if ('_header' === $value) { - return strtolower($key); - } - - if (null === $value) { - return $this->translator->trans('no data'); - } - - $country = $countryRepository->find($value); - - return $this->translatableStringHelper->localize( - $country->getName() - ); - }; - - case 'address_country_name': return function ($value) use ($key) { if ('_header' === $value) { return strtolower($key); @@ -209,25 +204,16 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou return ''; } - return $this->translatableStringHelper->localize(json_decode($value, true)); - }; + $country = $this->countryRepository->find($value); - case 'address_isnoaddress': - return static function (?string $value): string { - if ('_header' === $value) { - return 'address.address_homeless'; - } - - if (null !== $value) { - return 'X'; - } - - return ''; + return $this->translatableStringHelper->localize( + $country->getName() + ); }; default: // for fields which are associated with person - if (in_array($key, $this->fields, true)) { + if (in_array($key, self::FIELDS, true)) { return static function ($value) use ($key) { if ('_header' === $value) { return strtolower($key); @@ -246,9 +232,13 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou $fields = []; foreach ($data['fields'] as $key) { - if (in_array($key, $this->fields, true)) { - $fields[] = $key; + if (substr($key, 0, strlen('address')) === 'address') { + $fields = array_merge($fields, $this->addressHelper->getKeys(0b01111111, 'address_')); + + continue; } + + $fields[] = $key; } // add the key from slugs and return @@ -270,6 +260,9 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou return Declarations::PERSON_TYPE; } + /** + * @param array{fields: string[], address_date: DateTimeImmutable} $data + */ public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { $centers = array_map(static function ($el) { @@ -284,36 +277,57 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou $qb = $this->entityManager->createQueryBuilder(); - foreach ($this->fields as $f) { - if (in_array($f, $data['fields'], true)) { - switch ($f) { - case 'countryOfBirth': - case 'nationality': - $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f)); + $qb + ->from(Person::class, 'person') + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM ' . Person\PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) + ) + ->setParameter('authorized_centers', $centers); - break; + foreach (self::FIELDS as $f) { + if (!in_array($f, $data['fields'], true)) { + continue; + } - case 'address_street_address_1': - case 'address_street_address_2': - case 'address_valid_from': - case 'address_postcode_label': - case 'address_postcode_code': - case 'address_country_name': - case 'address_country_code': - case 'address_isnoaddress': - $qb->addSelect(sprintf( - 'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s', - // get the part after address_ - strtoupper(substr($f, 8)), - $f - )); - $qb->setParameter('address_date', $data['address_date']); + switch ($f) { + case 'countryOfBirth': + case 'nationality': + $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f)); - break; + break; - default: - $qb->addSelect(sprintf('person.%s as %s', $f, $f)); - } + case 'address': + foreach ($this->addressHelper->getKeys(0b01111111, 'address_') as $key) { + $qb + ->addSelect(sprintf('IDENTITY(currentPersonAddress.address) AS %s', $key)); + } + + if (!(in_array('currentPersonAddress', $qb->getAllAliases(), true))) { + $qb + ->leftJoin('person.currentPersonAddress', 'currentPersonAddress') + ->andWhere( + $qb->expr()->orX( + // no address at this time + $qb->expr()->isNull('currentPersonAddress'), + // there is one address... + $qb->expr()->andX( + $qb->expr()->lte('currentPersonAddress.validFrom', ':address_date'), + $qb->expr()->orX( + $qb->expr()->isNull('currentPersonAddress.validTo'), + $qb->expr()->gt('currentPersonAddress.validTo', ':address_date') + ) + ) + ) + ) + ->setParameter('address_date', $data['address_date']); + } + + break; + + default: + $qb->addSelect(sprintf('person.%s as %s', $f, $f)); } } @@ -345,12 +359,6 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } } - $qb - ->from('ChillPersonBundle:Person', 'person') - ->join('person.center', 'center') - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - return $qb; } @@ -368,7 +376,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou { // get the field starting with address_ $addressFields = array_filter( - $this->fields, + self::FIELDS, static fn (string $el): bool => substr($el, 0, 8) === 'address_' ); From f434cc5c0251a3d2e2f919653d6b12c008d77049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 26 Oct 2022 12:47:32 +0200 Subject: [PATCH 19/99] Fixed: [list person] fix list person and add new fields --- phpstan-critical.neon | 10 - phpstan-types.neon | 5 - .../Export/Helper/ExportAddressHelper.php | 32 +- .../Repository/CivilityRepository.php | 43 ++- .../CivilityRepositoryInterface.php | 34 ++ .../Repository/LanguageRepository.php | 7 +- .../LanguageRepositoryInterface.php | 37 ++ .../translations/messages.fr.yml | 4 + .../Household/PersonHouseholdAddress.php | 2 +- .../Export/Export/ListPerson.php | 330 +++++++++++++++--- .../Repository/MaritalStatusRepository.php | 3 +- .../MaritalStatusRepositoryInterface.php | 27 ++ .../translations/messages.fr.yml | 15 + 13 files changed, 457 insertions(+), 92 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Repository/CivilityRepositoryInterface.php create mode 100644 src/Bundle/ChillMainBundle/Repository/LanguageRepositoryInterface.php create mode 100644 src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepositoryInterface.php diff --git a/phpstan-critical.neon b/phpstan-critical.neon index 1dc516834..bfbb2dc7c 100644 --- a/phpstan-critical.neon +++ b/phpstan-critical.neon @@ -5,11 +5,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php - - - message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Household\\\\PersonHouseholdAddress\\:\\:\\$relation\\.$#" - count: 1 - path: src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php - - message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\AccompanyingPeriod\\:\\:\\$work\\.$#" count: 1 @@ -30,11 +25,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php - - - message: "#^Undefined variable\\: \\$choiceSlug$#" - count: 1 - path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php - - message: "#^Undefined variable\\: \\$choiceSlug$#" count: 1 diff --git a/phpstan-types.neon b/phpstan-types.neon index a0493ce0b..bf2ece912 100644 --- a/phpstan-types.neon +++ b/phpstan-types.neon @@ -340,11 +340,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 2 - path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 09aaa7a1d..6c6fcb76e 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -20,32 +20,32 @@ use Symfony\Component\PropertyAccess\PropertyAccessor; use function strlen; /** - * Helps to load addresses and format them in list + * Helps to load addresses and format them in list. */ class ExportAddressHelper { - public const ATTRIBUTES = 0b01000000; + public const F_AS_STRING = 0b00010000; - public const BUILDING = 0b00001000; + public const F_ATTRIBUTES = 0b01000000; - public const COUNTRY = 0b00000001; + public const F_BUILDING = 0b00001000; - public const GEOM = 0b00100000; + public const F_COUNTRY = 0b00000001; - public const POSTAL_CODE = 0b00000010; + public const F_GEOM = 0b00100000; - public const STREET = 0b00000100; + public const F_POSTAL_CODE = 0b00000010; - public const STRING = 0b00010000; + public const F_STREET = 0b00000100; private const ALL = [ - 'country' => self::COUNTRY, - 'postal_code' => self::POSTAL_CODE, - 'street' => self::STREET, - 'building' => self::BUILDING, - 'string' => self::STRING, - 'geom' => self::GEOM, - 'attributes' => self::ATTRIBUTES, + 'country' => self::F_COUNTRY, + 'postal_code' => self::F_POSTAL_CODE, + 'street' => self::F_STREET, + 'building' => self::F_BUILDING, + 'string' => self::F_AS_STRING, + 'geom' => self::F_GEOM, + 'attributes' => self::F_ATTRIBUTES, ]; private const COLUMN_MAPPING = [ @@ -78,6 +78,8 @@ class ExportAddressHelper } /** + * @param self::F_* $params + * * @return array|string[] */ public function getKeys(int $params, string $prefix = ''): array diff --git a/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php b/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php index 385488839..70b4a2bc4 100644 --- a/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php @@ -12,19 +12,40 @@ declare(strict_types=1); namespace Chill\MainBundle\Repository; use Chill\MainBundle\Entity\Civility; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; -/** - * @method Civility|null find($id, $lockMode = null, $lockVersion = null) - * @method Civility|null findOneBy(array $criteria, array $orderBy = null) - * @method Civility[] findAll() - * @method Civility[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class CivilityRepository extends ServiceEntityRepository +class CivilityRepository implements CivilityRepositoryInterface { - public function __construct(ManagerRegistry $registry) + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $entityManager) { - parent::__construct($registry, Civility::class); + $this->repository = $entityManager->getRepository($this->getClassName()); + } + + public function find($id): ?Civility + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?Civility + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return Civility::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/CivilityRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/CivilityRepositoryInterface.php new file mode 100644 index 000000000..5d687ac7e --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/CivilityRepositoryInterface.php @@ -0,0 +1,34 @@ +repository = $entityManager->getRepository(Language::class); + $this->repository = $entityManager->getRepository($this->getClassName()); } public function find($id, $lockMode = null, $lockVersion = null): ?Language @@ -54,7 +53,7 @@ final class LanguageRepository implements ObjectRepository return $this->repository->findOneBy($criteria, $orderBy); } - public function getClassName() + public function getClassName(): string { return Language::class; } diff --git a/src/Bundle/ChillMainBundle/Repository/LanguageRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/LanguageRepositoryInterface.php new file mode 100644 index 000000000..397b264e4 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/LanguageRepositoryInterface.php @@ -0,0 +1,37 @@ +relation; + return $this->household; } public function getPerson(): ?Person diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index e799a53e4..631e3b69a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -20,15 +20,20 @@ use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Repository\CivilityRepositoryInterface; use Chill\MainBundle\Repository\CountryRepository; +use Chill\MainBundle\Repository\LanguageRepositoryInterface; +use Chill\MainBundle\Repository\UserRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Export\Declarations; +use Chill\PersonBundle\Repository\MaritalStatusRepositoryInterface; use Chill\PersonBundle\Security\Authorization\PersonVoter; use DateTime; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; use Exception; use PhpOffice\PhpSpreadsheet\Shared\Date; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -44,7 +49,6 @@ use function array_merge; use function count; use function in_array; use function strlen; -use function strtolower; use function uniqid; /** @@ -54,42 +58,89 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou { public const FIELDS = [ 'id', + 'civility', 'firstName', 'lastName', 'birthdate', - 'placeOfBirth', 'gender', 'memo', 'email', 'phonenumber', - 'mobilenumber', 'contactInfo', 'countryOfBirth', 'nationality', - 'address', + 'center', + 'deathdate', + 'placeOfBirth', + 'gender', + 'genderComment', + 'maritalStatus', + 'maritalStatusComment', + 'maritalStatusDate', + 'memo', + 'email', + 'phonenumber', + 'mobilenumber', + 'numberOfChildren', + 'contactInfo', + 'countryOfBirth', + 'nationality', + // add full addresses + 'address_fields', + // add a list of spoken languages + 'spokenLanguages', + // add household id + 'household_id', + // add created at, created by, updated at, and updated by + 'lifecycleUpdate', ]; + private const HELPER_ATTRIBUTES = + ExportAddressHelper::F_ATTRIBUTES | + ExportAddressHelper::F_BUILDING | + ExportAddressHelper::F_COUNTRY | + ExportAddressHelper::F_GEOM | + ExportAddressHelper::F_POSTAL_CODE | + ExportAddressHelper::F_STREET | + ExportAddressHelper::F_AS_STRING; + private ExportAddressHelper $addressHelper; + private CivilityRepositoryInterface $civilityRepository; + private CountryRepository $countryRepository; private CustomFieldProvider $customFieldProvider; private EntityManagerInterface $entityManager; + private LanguageRepositoryInterface $languageRepository; + + private MaritalStatusRepositoryInterface $maritalStatusRepository; + private $slugs = []; private TranslatableStringHelper $translatableStringHelper; private TranslatorInterface $translator; + private UserRepositoryInterface $userRepository; + public function __construct( - CountryRepository $countryRepository, ExportAddressHelper $addressHelper, + CivilityRepositoryInterface $civilityRepository, + CountryRepository $countryRepository, + CustomFieldProvider $customFieldProvider, EntityManagerInterface $em, - TranslatorInterface $translator, + LanguageRepositoryInterface $languageRepository, + MaritalStatusRepositoryInterface $maritalStatusRepository, TranslatableStringHelper $translatableStringHelper, - CustomFieldProvider $customFieldProvider + TranslatorInterface $translator, + UserRepositoryInterface $userRepository ) { $this->addressHelper = $addressHelper; + $this->civilityRepository = $civilityRepository; $this->countryRepository = $countryRepository; $this->entityManager = $em; + $this->languageRepository = $languageRepository; + $this->maritalStatusRepository = $maritalStatusRepository; $this->translator = $translator; $this->translatableStringHelper = $translatableStringHelper; $this->customFieldProvider = $customFieldProvider; + $this->userRepository = $userRepository; } public function buildForm(FormBuilderInterface $builder) @@ -110,7 +161,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou 'label' => 'Fields to include in export', 'choice_attr' => static function (string $val): array { // add a 'data-display-target' for address fields - if (substr($val, 0, 7) === 'address') { + if (substr($val, 0, 7) === 'address' || 'center' === $val || 'household' === $val) { return ['data-display-target' => 'address_date']; } @@ -130,7 +181,8 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou // add a date field for addresses $builder->add('address_date', ChillDateType::class, [ - 'label' => 'Address valid at this date', + 'label' => 'Data valid at this date', + 'help' => 'Data regarding center, addresses, and so on will be computed at this date', 'data' => new DateTimeImmutable(), 'input' => 'datetime_immutable', ]); @@ -153,17 +205,21 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou public function getLabels($key, array $values, $data) { - if (substr($key, 0, strlen('address')) === 'address') { - return $this->addressHelper->getLabel($key, $values, $data, 'address_'); + if (substr($key, 0, strlen('address_fields')) === 'address_fields') { + return $this->addressHelper->getLabel($key, $values, $data, 'address_fields'); } switch ($key) { case 'birthdate': + case 'deathdate': + case 'maritalStatusDate': + case 'createdAt': + case 'updatedAt': // for birthdate, we have to transform the string into a date // to format the date correctly. - return static function ($value) { + return function ($value) use ($key) { if ('_header' === $value) { - return 'birthdate'; + return $this->translator->trans($key); } if (null === $value) { @@ -172,32 +228,120 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou // warning: won't work with DateTimeImmutable as we reset time a few lines later $date = DateTime::createFromFormat('Y-m-d', $value); + $hasTime = false; + + if (false === $date) { + $date = DateTime::createFromFormat('Y-m-d H:i:s', $value); + $hasTime = true; + } + // check that the creation could occurs. if (false === $date) { throw new Exception(sprintf('The value %s could ' . 'not be converted to %s', $value, DateTime::class)); } - $date->setTime(0, 0, 0); + if (!$hasTime) { + $date->setTime(0, 0, 0); + } return $date; }; + case 'createdBy': + case 'updatedBy': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + return $this->userRepository->find($value)->getLabel(); + }; + + case 'civility': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $civility = $this->civilityRepository->find($value); + + if (null === $civility) { + return ''; + } + + return $this->translatableStringHelper->localize($civility->getName()); + }; + case 'gender': // for gender, we have to translate men/women statement - return function ($value) { + return function ($value) use ($key) { if ('_header' === $value) { - return 'gender'; + return $this->translator->trans($key); } return $this->translator->trans($value); }; + case 'maritalStatus': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $maritalStatus = $this->maritalStatusRepository->find($value); + + return $this->translatableStringHelper->localize($maritalStatus->getName()); + }; + + case 'spokenLanguages': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $ids = json_decode($value); + + return + implode( + '|', + array_map(function ($id) { + if (null === $id) { + return ''; + } + + $lang = $this->languageRepository->find($id); + + if (null === $lang) { + return null; + } + + return $this->translatableStringHelper->localize($lang->getName()); + }, $ids) + ); + }; + case 'countryOfBirth': case 'nationality': return function ($value) use ($key) { if ('_header' === $value) { - return strtolower($key); + return $this->translator->trans($key); } if (null === $value) { @@ -214,9 +358,9 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou default: // for fields which are associated with person if (in_array($key, self::FIELDS, true)) { - return static function ($value) use ($key) { + return function ($value) use ($key) { if ('_header' === $value) { - return strtolower($key); + return $this->translator->trans($key); } return $value; @@ -231,9 +375,19 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou { $fields = []; - foreach ($data['fields'] as $key) { - if (substr($key, 0, strlen('address')) === 'address') { - $fields = array_merge($fields, $this->addressHelper->getKeys(0b01111111, 'address_')); + foreach (self::FIELDS as $key) { + if (!in_array($key, $data['fields'], true)) { + continue; + } + + if (substr($key, 0, strlen('address_fields')) === 'address_fields') { + $fields = array_merge($fields, $this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields')); + + continue; + } + + if ('lifecycleUpdate' === $key) { + $fields = array_merge($fields, ['createdAt', 'createdBy', 'updatedAt', 'updatedBy']); continue; } @@ -286,8 +440,10 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou ) ->setParameter('authorized_centers', $centers); + $fields = $data['fields']; + foreach (self::FIELDS as $f) { - if (!in_array($f, $data['fields'], true)) { + if (!in_array($f, $fields, true)) { continue; } @@ -298,31 +454,90 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou break; - case 'address': - foreach ($this->addressHelper->getKeys(0b01111111, 'address_') as $key) { + case 'address_fields': + foreach ($this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields') as $key) { $qb - ->addSelect(sprintf('IDENTITY(currentPersonAddress.address) AS %s', $key)); + ->addSelect(sprintf('IDENTITY(personHouseholdAddress.address) AS %s', $key)); } - if (!(in_array('currentPersonAddress', $qb->getAllAliases(), true))) { - $qb - ->leftJoin('person.currentPersonAddress', 'currentPersonAddress') - ->andWhere( - $qb->expr()->orX( - // no address at this time - $qb->expr()->isNull('currentPersonAddress'), - // there is one address... - $qb->expr()->andX( - $qb->expr()->lte('currentPersonAddress.validFrom', ':address_date'), - $qb->expr()->orX( - $qb->expr()->isNull('currentPersonAddress.validTo'), - $qb->expr()->gt('currentPersonAddress.validTo', ':address_date') - ) + $this->addCurrentAddressAt($qb, $data['address_date']); + + break; + + case 'spokenLanguages': + $qb + ->leftJoin('person.spokenLanguages', 'spokenLanguage') + ->addSelect('AGGREGATE(spokenLanguage.id) AS spokenLanguages') + ->addGroupBy('person'); + + if (in_array('center', $fields, true)) { + $qb->addGroupBy('center'); + } + + if (in_array('address_fields', $fields, true)) { + $qb->addGroupBy('address_fieldsid'); + } + + if (in_array('household_id', $fields, true)) { + $qb->addGroupBy('household_id'); + } + + break; + + case 'household_id': + $qb + ->addSelect('IDENTITY(personHouseholdAddress.household) AS household_id'); + + $this->addCurrentAddressAt($qb, $data['address_date']); + + break; + + case 'center': + $qb + ->addSelect('IDENTITY(centerHistory.center) AS center') + ->leftJoin('person.centerHistory', 'centerHistory') + ->andWhere( + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory'), + $qb->expr()->andX( + $qb->expr()->lte('centerHistory.startDate', ':address_date'), + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory.endDate'), + $qb->expr()->gte('centerHistory.endDate', ':address_date') ) ) ) - ->setParameter('address_date', $data['address_date']); - } + ) + ->setParameter('address_date', $data['address_date']); + + break; + + case 'lifecycleUpdate': + $qb + ->addSelect('person.createdAt AS createdAt') + ->addSelect('IDENTITY(person.createdBy) AS createdBy') + ->addSelect('person.updatedAt AS updatedAt') + ->addSelect('IDENTITY(person.updatedBy) AS updatedBy'); + + break; + + case 'genderComment': + $qb->addSelect('person.genderComment.comment AS genderComment'); + + break; + + case 'maritalStatus': + $qb->addSelect('IDENTITY(person.maritalStatus) AS maritalStatus'); + + break; + + case 'maritalStatusComment': + $qb->addSelect('person.maritalStatusComment.comment AS maritalStatusComment'); + + break; + + case 'civility': + $qb->addSelect('IDENTITY(person.civility) AS civility'); break; @@ -332,6 +547,10 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } foreach ($this->getCustomFields() as $cf) { + if (!in_array($cf->getSlug(), $fields, true)) { + continue; + } + $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); if ($cfType instanceof CustomFieldChoice && $cfType->isMultiple($cf)) { @@ -383,7 +602,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou // check if there is one field starting with address in data if (count(array_intersect($data['fields'], $addressFields)) > 0) { // if a field address is checked, the date must not be empty - if (empty($data['address_date'])) { + if (!$data['address_date'] instanceof DateTimeImmutable) { $context ->buildViolation('You must set this date if an address is checked') ->atPath('address_date') @@ -392,6 +611,29 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } } + private function addCurrentAddressAt(QueryBuilder $qb, DateTimeImmutable $date): void + { + if (!(in_array('personHouseholdAddress', $qb->getAllAliases(), true))) { + $qb + ->leftJoin('person.householdAddresses', 'personHouseholdAddress') + ->andWhere( + $qb->expr()->orX( + // no address at this time + $qb->expr()->isNull('personHouseholdAddress'), + // there is one address... + $qb->expr()->andX( + $qb->expr()->lte('personHouseholdAddress.validFrom', ':address_date'), + $qb->expr()->orX( + $qb->expr()->isNull('personHouseholdAddress.validTo'), + $qb->expr()->gt('personHouseholdAddress.validTo', ':address_date') + ) + ) + ) + ) + ->setParameter('address_date', $date); + } + } + private function DQLToSlug($cleanedSlug) { return $this->slugs[$cleanedSlug]['slug']; @@ -464,7 +706,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou . ' | ' . $label; } - if ('_other' === $slugChoice && $cfType->isChecked($cf, $choiceSlug, $decoded)) { + if ('_other' === $slugChoice && $cfType->isChecked($cf, $slugChoice, $decoded)) { return $cfType->extractOtherValue($cf, $decoded); } diff --git a/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php index 1df23fa31..8697f9346 100644 --- a/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php @@ -14,9 +14,8 @@ namespace Chill\PersonBundle\Repository; use Chill\PersonBundle\Entity\MaritalStatus; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; -use Doctrine\Persistence\ObjectRepository; -class MaritalStatusRepository implements ObjectRepository +class MaritalStatusRepository implements MaritalStatusRepositoryInterface { private EntityRepository $repository; diff --git a/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepositoryInterface.php new file mode 100644 index 000000000..1f51060e9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepositoryInterface.php @@ -0,0 +1,27 @@ + Date: Wed, 26 Oct 2022 13:30:16 +0200 Subject: [PATCH 20/99] DX: Refactor ListPerson to extract methods linked to label and select --- .../Export/Export/ListPerson.php | 383 +--------------- .../Export/Helper/ListPersonHelper.php | 428 ++++++++++++++++++ 2 files changed, 443 insertions(+), 368 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 631e3b69a..eb746e122 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -20,28 +20,20 @@ use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Form\Type\ChillDateType; -use Chill\MainBundle\Repository\CivilityRepositoryInterface; -use Chill\MainBundle\Repository\CountryRepository; -use Chill\MainBundle\Repository\LanguageRepositoryInterface; -use Chill\MainBundle\Repository\UserRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Export\Declarations; -use Chill\PersonBundle\Repository\MaritalStatusRepositoryInterface; +use Chill\PersonBundle\Export\Helper\ListPersonHelper; use Chill\PersonBundle\Security\Authorization\PersonVoter; -use DateTime; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; -use Doctrine\ORM\QueryBuilder; -use Exception; use PhpOffice\PhpSpreadsheet\Shared\Date; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Contracts\Translation\TranslatorInterface; use function addcslashes; use function array_key_exists; use function array_keys; @@ -56,96 +48,35 @@ use function uniqid; */ class ListPerson implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface { - public const FIELDS = [ - 'id', - 'civility', - 'firstName', - 'lastName', - 'birthdate', - 'center', - 'deathdate', - 'placeOfBirth', - 'gender', - 'genderComment', - 'maritalStatus', - 'maritalStatusComment', - 'maritalStatusDate', - 'memo', - 'email', - 'phonenumber', - 'mobilenumber', - 'numberOfChildren', - 'contactInfo', - 'countryOfBirth', - 'nationality', - // add full addresses - 'address_fields', - // add a list of spoken languages - 'spokenLanguages', - // add household id - 'household_id', - // add created at, created by, updated at, and updated by - 'lifecycleUpdate', - ]; - - private const HELPER_ATTRIBUTES = - ExportAddressHelper::F_ATTRIBUTES | - ExportAddressHelper::F_BUILDING | - ExportAddressHelper::F_COUNTRY | - ExportAddressHelper::F_GEOM | - ExportAddressHelper::F_POSTAL_CODE | - ExportAddressHelper::F_STREET | - ExportAddressHelper::F_AS_STRING; - private ExportAddressHelper $addressHelper; - private CivilityRepositoryInterface $civilityRepository; - - private CountryRepository $countryRepository; - private CustomFieldProvider $customFieldProvider; private EntityManagerInterface $entityManager; - private LanguageRepositoryInterface $languageRepository; - - private MaritalStatusRepositoryInterface $maritalStatusRepository; + private ListPersonHelper $listPersonHelper; private $slugs = []; private TranslatableStringHelper $translatableStringHelper; - private TranslatorInterface $translator; - - private UserRepositoryInterface $userRepository; - public function __construct( ExportAddressHelper $addressHelper, - CivilityRepositoryInterface $civilityRepository, - CountryRepository $countryRepository, CustomFieldProvider $customFieldProvider, + ListPersonHelper $listPersonHelper, EntityManagerInterface $em, - LanguageRepositoryInterface $languageRepository, - MaritalStatusRepositoryInterface $maritalStatusRepository, - TranslatableStringHelper $translatableStringHelper, - TranslatorInterface $translator, - UserRepositoryInterface $userRepository + TranslatableStringHelper $translatableStringHelper ) { $this->addressHelper = $addressHelper; - $this->civilityRepository = $civilityRepository; - $this->countryRepository = $countryRepository; - $this->entityManager = $em; - $this->languageRepository = $languageRepository; - $this->maritalStatusRepository = $maritalStatusRepository; - $this->translator = $translator; - $this->translatableStringHelper = $translatableStringHelper; $this->customFieldProvider = $customFieldProvider; - $this->userRepository = $userRepository; + $this->listPersonHelper = $listPersonHelper; + $this->entityManager = $em; + $this->translatableStringHelper = $translatableStringHelper; } public function buildForm(FormBuilderInterface $builder) { - $choices = array_combine(self::FIELDS, self::FIELDS); + $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); foreach ($this->getCustomFields() as $cf) { $choices[$this->translatableStringHelper->localize($cf->getName())] @@ -205,183 +136,24 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou public function getLabels($key, array $values, $data) { - if (substr($key, 0, strlen('address_fields')) === 'address_fields') { - return $this->addressHelper->getLabel($key, $values, $data, 'address_fields'); + if (in_array($key, $this->listPersonHelper->getAllPossibleFields(), true)) { + return $this->listPersonHelper->getLabels($key, $values, $data); } - switch ($key) { - case 'birthdate': - case 'deathdate': - case 'maritalStatusDate': - case 'createdAt': - case 'updatedAt': - // for birthdate, we have to transform the string into a date - // to format the date correctly. - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - // warning: won't work with DateTimeImmutable as we reset time a few lines later - $date = DateTime::createFromFormat('Y-m-d', $value); - $hasTime = false; - - if (false === $date) { - $date = DateTime::createFromFormat('Y-m-d H:i:s', $value); - $hasTime = true; - } - - // check that the creation could occurs. - if (false === $date) { - throw new Exception(sprintf('The value %s could ' - . 'not be converted to %s', $value, DateTime::class)); - } - - if (!$hasTime) { - $date->setTime(0, 0, 0); - } - - return $date; - }; - - case 'createdBy': - case 'updatedBy': - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - return $this->userRepository->find($value)->getLabel(); - }; - - case 'civility': - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - $civility = $this->civilityRepository->find($value); - - if (null === $civility) { - return ''; - } - - return $this->translatableStringHelper->localize($civility->getName()); - }; - - case 'gender': - // for gender, we have to translate men/women statement - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - return $this->translator->trans($value); - }; - - case 'maritalStatus': - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - $maritalStatus = $this->maritalStatusRepository->find($value); - - return $this->translatableStringHelper->localize($maritalStatus->getName()); - }; - - case 'spokenLanguages': - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - $ids = json_decode($value); - - return - implode( - '|', - array_map(function ($id) { - if (null === $id) { - return ''; - } - - $lang = $this->languageRepository->find($id); - - if (null === $lang) { - return null; - } - - return $this->translatableStringHelper->localize($lang->getName()); - }, $ids) - ); - }; - - case 'countryOfBirth': - case 'nationality': - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - if (null === $value) { - return ''; - } - - $country = $this->countryRepository->find($value); - - return $this->translatableStringHelper->localize( - $country->getName() - ); - }; - - default: - // for fields which are associated with person - if (in_array($key, self::FIELDS, true)) { - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - return $value; - }; - } - - return $this->getLabelForCustomField($key, $values, $data); - } + return $this->getLabelForCustomField($key, $values, $data); } public function getQueryKeys($data) { $fields = []; - foreach (self::FIELDS as $key) { + foreach (ListPersonHelper::FIELDS as $key) { if (!in_array($key, $data['fields'], true)) { continue; } if (substr($key, 0, strlen('address_fields')) === 'address_fields') { - $fields = array_merge($fields, $this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields')); + $fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields')); continue; } @@ -442,109 +214,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou $fields = $data['fields']; - foreach (self::FIELDS as $f) { - if (!in_array($f, $fields, true)) { - continue; - } - - switch ($f) { - case 'countryOfBirth': - case 'nationality': - $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f)); - - break; - - case 'address_fields': - foreach ($this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields') as $key) { - $qb - ->addSelect(sprintf('IDENTITY(personHouseholdAddress.address) AS %s', $key)); - } - - $this->addCurrentAddressAt($qb, $data['address_date']); - - break; - - case 'spokenLanguages': - $qb - ->leftJoin('person.spokenLanguages', 'spokenLanguage') - ->addSelect('AGGREGATE(spokenLanguage.id) AS spokenLanguages') - ->addGroupBy('person'); - - if (in_array('center', $fields, true)) { - $qb->addGroupBy('center'); - } - - if (in_array('address_fields', $fields, true)) { - $qb->addGroupBy('address_fieldsid'); - } - - if (in_array('household_id', $fields, true)) { - $qb->addGroupBy('household_id'); - } - - break; - - case 'household_id': - $qb - ->addSelect('IDENTITY(personHouseholdAddress.household) AS household_id'); - - $this->addCurrentAddressAt($qb, $data['address_date']); - - break; - - case 'center': - $qb - ->addSelect('IDENTITY(centerHistory.center) AS center') - ->leftJoin('person.centerHistory', 'centerHistory') - ->andWhere( - $qb->expr()->orX( - $qb->expr()->isNull('centerHistory'), - $qb->expr()->andX( - $qb->expr()->lte('centerHistory.startDate', ':address_date'), - $qb->expr()->orX( - $qb->expr()->isNull('centerHistory.endDate'), - $qb->expr()->gte('centerHistory.endDate', ':address_date') - ) - ) - ) - ) - ->setParameter('address_date', $data['address_date']); - - break; - - case 'lifecycleUpdate': - $qb - ->addSelect('person.createdAt AS createdAt') - ->addSelect('IDENTITY(person.createdBy) AS createdBy') - ->addSelect('person.updatedAt AS updatedAt') - ->addSelect('IDENTITY(person.updatedBy) AS updatedBy'); - - break; - - case 'genderComment': - $qb->addSelect('person.genderComment.comment AS genderComment'); - - break; - - case 'maritalStatus': - $qb->addSelect('IDENTITY(person.maritalStatus) AS maritalStatus'); - - break; - - case 'maritalStatusComment': - $qb->addSelect('person.maritalStatusComment.comment AS maritalStatusComment'); - - break; - - case 'civility': - $qb->addSelect('IDENTITY(person.civility) AS civility'); - - break; - - default: - $qb->addSelect(sprintf('person.%s as %s', $f, $f)); - } - } + $this->listPersonHelper->addSelect($qb, $fields, $data['address_date']); foreach ($this->getCustomFields() as $cf) { if (!in_array($cf->getSlug(), $fields, true)) { @@ -595,7 +265,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou { // get the field starting with address_ $addressFields = array_filter( - self::FIELDS, + ListPersonHelper::FIELDS, static fn (string $el): bool => substr($el, 0, 8) === 'address_' ); @@ -611,29 +281,6 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } } - private function addCurrentAddressAt(QueryBuilder $qb, DateTimeImmutable $date): void - { - if (!(in_array('personHouseholdAddress', $qb->getAllAliases(), true))) { - $qb - ->leftJoin('person.householdAddresses', 'personHouseholdAddress') - ->andWhere( - $qb->expr()->orX( - // no address at this time - $qb->expr()->isNull('personHouseholdAddress'), - // there is one address... - $qb->expr()->andX( - $qb->expr()->lte('personHouseholdAddress.validFrom', ':address_date'), - $qb->expr()->orX( - $qb->expr()->isNull('personHouseholdAddress.validTo'), - $qb->expr()->gt('personHouseholdAddress.validTo', ':address_date') - ) - ) - ) - ) - ->setParameter('address_date', $date); - } - } - private function DQLToSlug($cleanedSlug) { return $this->slugs[$cleanedSlug]['slug']; diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php new file mode 100644 index 000000000..7a14e0446 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php @@ -0,0 +1,428 @@ +addressHelper = $addressHelper; + $this->civilityRepository = $civilityRepository; + $this->countryRepository = $countryRepository; + $this->languageRepository = $languageRepository; + $this->maritalStatusRepository = $maritalStatusRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->translator = $translator; + $this->userRepository = $userRepository; + } + + /** + * @param array|value-of[] $fields + */ + public function addSelect(QueryBuilder $qb, array $fields, DateTimeImmutable $computedDate): void + { + foreach (ListPersonHelper::FIELDS as $f) { + if (!in_array($f, $fields, true)) { + continue; + } + + switch ($f) { + case 'countryOfBirth': + case 'nationality': + $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f)); + + break; + + case 'address_fields': + foreach ($this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields') as $key) { + $qb + ->addSelect(sprintf('IDENTITY(personHouseholdAddress.address) AS %s', $key)); + } + + $this->addCurrentAddressAt($qb, $computedDate); + + break; + + case 'spokenLanguages': + $qb + ->leftJoin('person.spokenLanguages', 'spokenLanguage') + ->addSelect('AGGREGATE(spokenLanguage.id) AS spokenLanguages') + ->addGroupBy('person'); + + if (in_array('center', $fields, true)) { + $qb->addGroupBy('center'); + } + + if (in_array('address_fields', $fields, true)) { + $qb->addGroupBy('address_fieldsid'); + } + + if (in_array('household_id', $fields, true)) { + $qb->addGroupBy('household_id'); + } + + break; + + case 'household_id': + $qb + ->addSelect('IDENTITY(personHouseholdAddress.household) AS household_id'); + + $this->addCurrentAddressAt($qb, $computedDate); + + break; + + case 'center': + $qb + ->addSelect('IDENTITY(centerHistory.center) AS center') + ->leftJoin('person.centerHistory', 'centerHistory') + ->andWhere( + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory'), + $qb->expr()->andX( + $qb->expr()->lte('centerHistory.startDate', ':address_date'), + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory.endDate'), + $qb->expr()->gte('centerHistory.endDate', ':address_date') + ) + ) + ) + ) + ->setParameter('address_date', $computedDate); + + break; + + case 'lifecycleUpdate': + $qb + ->addSelect('person.createdAt AS createdAt') + ->addSelect('IDENTITY(person.createdBy) AS createdBy') + ->addSelect('person.updatedAt AS updatedAt') + ->addSelect('IDENTITY(person.updatedBy) AS updatedBy'); + + break; + + case 'genderComment': + $qb->addSelect('person.genderComment.comment AS genderComment'); + + break; + + case 'maritalStatus': + $qb->addSelect('IDENTITY(person.maritalStatus) AS maritalStatus'); + + break; + + case 'maritalStatusComment': + $qb->addSelect('person.maritalStatusComment.comment AS maritalStatusComment'); + + break; + + case 'civility': + $qb->addSelect('IDENTITY(person.civility) AS civility'); + + break; + + default: + $qb->addSelect(sprintf('person.%s as %s', $f, $f)); + } + } + } + + /** + * @return array|string[] + */ + public function getAllPossibleFields(): array + { + return array_merge( + self::FIELDS, + ['createdAt', 'createdBy', 'updatedAt', 'updatedBy'], + $this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields') + ); + } + + public function getLabels($key, array $values, $data): callable + { + if (substr($key, 0, strlen('address_fields')) === 'address_fields') { + return $this->addressHelper->getLabel($key, $values, $data, 'address_fields'); + } + + switch ($key) { + case 'birthdate': + case 'deathdate': + case 'maritalStatusDate': + case 'createdAt': + case 'updatedAt': + // for birthdate, we have to transform the string into a date + // to format the date correctly. + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + // warning: won't work with DateTimeImmutable as we reset time a few lines later + $date = DateTime::createFromFormat('Y-m-d', $value); + $hasTime = false; + + if (false === $date) { + $date = DateTime::createFromFormat('Y-m-d H:i:s', $value); + $hasTime = true; + } + + // check that the creation could occurs. + if (false === $date) { + throw new Exception(sprintf('The value %s could ' + . 'not be converted to %s', $value, DateTime::class)); + } + + if (!$hasTime) { + $date->setTime(0, 0, 0); + } + + return $date; + }; + + case 'createdBy': + case 'updatedBy': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + return $this->userRepository->find($value)->getLabel(); + }; + + case 'civility': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $civility = $this->civilityRepository->find($value); + + if (null === $civility) { + return ''; + } + + return $this->translatableStringHelper->localize($civility->getName()); + }; + + case 'gender': + // for gender, we have to translate men/women statement + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + return $this->translator->trans($value); + }; + + case 'maritalStatus': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $maritalStatus = $this->maritalStatusRepository->find($value); + + return $this->translatableStringHelper->localize($maritalStatus->getName()); + }; + + case 'spokenLanguages': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $ids = json_decode($value); + + return + implode( + '|', + array_map(function ($id) { + if (null === $id) { + return ''; + } + + $lang = $this->languageRepository->find($id); + + if (null === $lang) { + return null; + } + + return $this->translatableStringHelper->localize($lang->getName()); + }, $ids) + ); + }; + + case 'countryOfBirth': + case 'nationality': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value) { + return ''; + } + + $country = $this->countryRepository->find($value); + + return $this->translatableStringHelper->localize( + $country->getName() + ); + }; + + default: + // for fields which are associated with person + if (in_array($key, ListPersonHelper::FIELDS, true)) { + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + return $value; + }; + } + } + } + + private function addCurrentAddressAt(QueryBuilder $qb, DateTimeImmutable $date): void + { + if (!(in_array('personHouseholdAddress', $qb->getAllAliases(), true))) { + $qb + ->leftJoin('person.householdAddresses', 'personHouseholdAddress') + ->andWhere( + $qb->expr()->orX( + // no address at this time + $qb->expr()->isNull('personHouseholdAddress'), + // there is one address... + $qb->expr()->andX( + $qb->expr()->lte('personHouseholdAddress.validFrom', ':address_date'), + $qb->expr()->orX( + $qb->expr()->isNull('personHouseholdAddress.validTo'), + $qb->expr()->gt('personHouseholdAddress.validTo', ':address_date') + ) + ) + ) + ) + ->setParameter('address_date', $date); + } + } +} From cf7d0c1bdb7176b163d84f7077016458a1198551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 26 Oct 2022 14:57:10 +0200 Subject: [PATCH 21/99] Fixed: [export][acl][Social issue filter] fix type for retrieving data from form --- .../Filter/AccompanyingCourseFilters/SocialIssueFilter.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php index 141a1a2db..917e129bf 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Form\Type\PickSocialIssueType; @@ -31,15 +30,11 @@ class SocialIssueFilter implements FilterInterface private SocialIssueRender $socialIssueRender; - private TranslatableStringHelper $translatableStringHelper; - public function __construct( TranslatorInterface $translator, - TranslatableStringHelper $translatableStringHelper, SocialIssueRender $socialIssueRender ) { $this->translator = $translator; - $this->translatableStringHelper = $translatableStringHelper; $this->socialIssueRender = $socialIssueRender; } @@ -59,7 +54,7 @@ class SocialIssueFilter implements FilterInterface $qb->andWhere($clause) ->setParameter( 'socialissues', - SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues']) + SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues']->toArray()) ); } From 4e55f1ede77cac731d77fcfc515733d37b95400f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 26 Oct 2022 14:58:28 +0200 Subject: [PATCH 22/99] DX: ensure that the return type is correct in ListPersonHelper --- .../Export/Helper/ListPersonHelper.php | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php index 7a14e0446..69f797c3d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php +++ b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php @@ -25,6 +25,7 @@ use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Exception; use PhpOffice\PhpSpreadsheet\Shared\Date; +use RuntimeException; use Symfony\Contracts\Translation\TranslatorInterface; use function in_array; use function strlen; @@ -390,16 +391,18 @@ class ListPersonHelper }; default: - // for fields which are associated with person - if (in_array($key, ListPersonHelper::FIELDS, true)) { - return function ($value) use ($key) { - if ('_header' === $value) { - return $this->translator->trans($key); - } - - return $value; - }; + if (!in_array($key, self::getAllPossibleFields(), true)) { + throw new RuntimeException("this key is not supported by this helper: {$key}"); } + + // for fields which are associated with person + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + return $value; + }; } } From d75ec92417d0f82b12aae3e8a33f9244326638ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 26 Oct 2022 14:59:06 +0200 Subject: [PATCH 23/99] Feature: [export] add a list of people having an accompanying period --- .../ListPersonWithAccompanyingPeriod.php | 218 ++++++++++++++++++ .../config/services/exports_person.yaml | 9 +- .../translations/messages.fr.yml | 5 +- 3 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php new file mode 100644 index 000000000..ce97ce662 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php @@ -0,0 +1,218 @@ +addressHelper = $addressHelper; + $this->listPersonHelper = $listPersonHelper; + $this->entityManager = $em; + } + + public function buildForm(FormBuilderInterface $builder) + { + $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); + + // Add a checkbox to select fields + $builder->add('fields', ChoiceType::class, [ + 'multiple' => true, + 'expanded' => true, + 'choices' => $choices, + 'label' => 'Fields to include in export', + 'choice_attr' => static function (string $val): array { + // add a 'data-display-target' for address fields + if (substr($val, 0, 7) === 'address' || 'center' === $val || 'household' === $val) { + return ['data-display-target' => 'address_date']; + } + + return []; + }, + 'constraints' => [new Callback([ + 'callback' => static function ($selected, ExecutionContextInterface $context) { + if (count($selected) === 0) { + $context->buildViolation('You must select at least one element') + ->atPath('fields') + ->addViolation(); + } + }, + ])], + 'data' => array_values($choices), + ]); + + // add a date field for addresses + $builder->add('address_date', ChillDateType::class, [ + 'label' => 'Data valid at this date', + 'help' => 'Data regarding center, addresses, and so on will be computed at this date', + 'data' => new DateTimeImmutable(), + 'input' => 'datetime_immutable', + ]); + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_LIST]; + } + + public function getDescription() + { + return 'export.list.person_with_acp.Create a list of people having an accompaying periods, according to various filters.'; + } + + public function getGroup(): string + { + return 'Exports of persons'; + } + + public function getLabels($key, array $values, $data) + { + return $this->listPersonHelper->getLabels($key, $values, $data); + } + + public function getQueryKeys($data) + { + $fields = []; + + foreach (ListPersonHelper::FIELDS as $key) { + if (!in_array($key, $data['fields'], true)) { + continue; + } + + if (substr($key, 0, strlen('address_fields')) === 'address_fields') { + $fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields')); + + continue; + } + + if ('lifecycleUpdate' === $key) { + $fields = array_merge($fields, ['createdAt', 'createdBy', 'updatedAt', 'updatedBy']); + + continue; + } + + $fields[] = $key; + } + + return $fields; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR); + } + + public function getTitle() + { + return 'export.list.person_with_acp.List peoples having an accompanying period'; + } + + public function getType() + { + return Declarations::PERSON_TYPE; + } + + /** + * @param array{fields: string[], address_date: DateTimeImmutable} $data + */ + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static function ($el) { + return $el['center']; + }, $acl); + + // throw an error if any fields are present + if (!array_key_exists('fields', $data)) { + throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields ' + . 'have been checked'); + } + + $qb = $this->entityManager->createQueryBuilder(); + + $qb->from(Person::class, 'person') + ->join('person.accompanyingPeriodParticipations', 'acppart') + ->join('acppart.accompanyingPeriod', 'acp') + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' + ) + )->setParameter('authorized_centers', $centers); + + $fields = $data['fields']; + + $this->listPersonHelper->addSelect($qb, $fields, $data['address_date']); + + return $qb; + } + + public function requiredRole(): string + { + return PersonVoter::LISTS; + } + + public function supportsModifiers() + { + return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN, Declarations::ACP_TYPE]; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + // get the field starting with address_ + $addressFields = array_filter( + ListPersonHelper::FIELDS, + static fn (string $el): bool => substr($el, 0, 8) === 'address_' + ); + + // check if there is one field starting with address in data + if (count(array_intersect($data['fields'], $addressFields)) > 0) { + // if a field address is checked, the date must not be empty + if (!$data['address_date'] instanceof DateTimeImmutable) { + $context + ->buildViolation('You must set this date if an address is checked') + ->atPath('address_date') + ->addViolation(); + } + } + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index ffffaf175..b9030ec62 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -15,13 +15,18 @@ services: tags: - { name: chill.export, alias: count_person_with_accompanying_course } - chill.person.export.list_person: - class: Chill\PersonBundle\Export\Export\ListPerson + Chill\PersonBundle\Export\Export\ListPerson: autowire: true autoconfigure: true tags: - { name: chill.export, alias: list_person } + Chill\PersonBundle\Export\Export\ListPersonWithAccompanyingPeriod: + autowire: true + autoconfigure: true + tags: + - { name: chill.export, alias: list_person_with_acp } + chill.person.export.list_person.duplicate: class: Chill\PersonBundle\Export\Export\ListPersonDuplicate arguments: diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 0b71d9698..5f43608ce 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1019,8 +1019,9 @@ export: Computation date for referrer: Date à laquelle le référent était actif by_referrer: Computation date for referrer: Date à laquelle le référent était actif - lists: - + list: + person_with_acp.List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement + Create a list of people having an accompaying periods, according to various filters.: Génère une liste des personnes ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager social_action: and children: et dérivés From 6ffe99a2be1196ead6eec156a99bce5bda0059f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 28 Oct 2022 22:25:53 +0200 Subject: [PATCH 24/99] Feature: [export] Add a list of accompanying periods --- .../ChillMainExtension.php | 4 + .../ChillMainBundle/Doctrine/DQL/STX.php | 37 ++ .../ChillMainBundle/Doctrine/DQL/STY.php | 37 ++ .../Export/Helper/DateTimeHelper.php | 60 +++ .../Export/Helper/ExportAddressHelper.php | 174 +++++--- .../Export/Helper/UserHelper.php | 43 ++ .../Export/Export/CountAccompanyingCourse.php | 2 +- .../Export/Export/ListAccompanyingPeriod.php | 416 ++++++++++++++++++ .../Export/Export/ListPerson.php | 2 +- .../ListPersonWithAccompanyingPeriod.php | 4 +- .../Export/Helper/ListPersonHelper.php | 42 +- .../config/services/exports_person.yaml | 6 + .../translations/messages.fr.yml | 44 +- 13 files changed, 778 insertions(+), 93 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Doctrine/DQL/STX.php create mode 100644 src/Bundle/ChillMainBundle/Doctrine/DQL/STY.php create mode 100644 src/Bundle/ChillMainBundle/Export/Helper/DateTimeHelper.php create mode 100644 src/Bundle/ChillMainBundle/Export/Helper/UserHelper.php create mode 100644 src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 17c6e0b64..7c63263ba 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -34,6 +34,8 @@ use Chill\MainBundle\Doctrine\DQL\Replace; use Chill\MainBundle\Doctrine\DQL\Similarity; use Chill\MainBundle\Doctrine\DQL\STContains; use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS; +use Chill\MainBundle\Doctrine\DQL\STX; +use Chill\MainBundle\Doctrine\DQL\STY; use Chill\MainBundle\Doctrine\DQL\ToChar; use Chill\MainBundle\Doctrine\DQL\Unaccent; use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator; @@ -242,6 +244,8 @@ class ChillMainExtension extends Extension implements 'STRICT_WORD_SIMILARITY_OPS' => StrictWordSimilarityOPS::class, 'ST_CONTAINS' => STContains::class, 'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class, + 'ST_X' => STX::class, + 'ST_Y' => STY::class, ], 'datetime_functions' => [ 'EXTRACT' => Extract::class, diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/STX.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/STX.php new file mode 100644 index 000000000..d5d8d0a3f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/STX.php @@ -0,0 +1,37 @@ +field->dispatch($sqlWalker)); + } + + public function parse(Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->field = $parser->ArithmeticExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/STY.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/STY.php new file mode 100644 index 000000000..e827da543 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/STY.php @@ -0,0 +1,37 @@ +field->dispatch($sqlWalker)); + } + + public function parse(Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->field = $parser->ArithmeticExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Export/Helper/DateTimeHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/DateTimeHelper.php new file mode 100644 index 000000000..86a2458b2 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/Helper/DateTimeHelper.php @@ -0,0 +1,60 @@ +translator = $translator; + } + + public function getLabel($header): callable + { + return function ($value) use ($header) { + if ('_header' === $value) { + return $this->translator->trans($header); + } + + if (null === $value) { + return ''; + } + + // warning: won't work with DateTimeImmutable as we reset time a few lines later + $date = DateTime::createFromFormat('Y-m-d', $value); + $hasTime = false; + + if (false === $date) { + $date = DateTime::createFromFormat('Y-m-d H:i:s', $value); + $hasTime = true; + } + + // check that the creation could occurs. + if (false === $date) { + throw new Exception(sprintf('The value %s could ' + . 'not be converted to %s', $value, DateTime::class)); + } + + if (!$hasTime) { + $date->setTime(0, 0, 0); + } + + return $date; + }; + } +} diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 6c6fcb76e..41443e3d8 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -14,9 +14,11 @@ namespace Chill\MainBundle\Export\Helper; use Chill\MainBundle\Repository\AddressRepository; use Chill\MainBundle\Templating\Entity\AddressRender; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessor; +use function in_array; use function strlen; /** @@ -24,6 +26,10 @@ use function strlen; */ class ExportAddressHelper { + public const F_ALL = + self::F_ATTRIBUTES | self::F_BUILDING | self::F_COUNTRY | + self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET; + public const F_AS_STRING = 0b00010000; public const F_ATTRIBUTES = 0b01000000; @@ -77,6 +83,87 @@ class ExportAddressHelper $this->addressRender = $addressRender; } + public function addSelectClauses(int $params, QueryBuilder $queryBuilder, $entityName = 'address', $prefix = 'add') + { + foreach (self::ALL as $key => $bitmask) { + if (($params & $bitmask) === $bitmask) { + foreach (self::COLUMN_MAPPING[$key] as $field) { + switch ($field) { + case 'id': + case '_as_string': + $queryBuilder->addSelect(sprintf('%s.id AS %s%s', $entityName, $prefix, $field)); + + break; + + case 'street': + case 'streetNumber': + case 'building': + case 'floor': + case 'corridor': + case 'steps': + case 'buildingName': + case 'flat': + case 'distribution': + case 'extra': + $queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $entityName, $field, $prefix, $field)); + + break; + + case 'country': + case 'postcode_name': + case 'postcode_code': + $postCodeAlias = sprintf('%spostcode_t', $prefix); + + if (!in_array($postCodeAlias, $queryBuilder->getAllAliases(), true)) { + $queryBuilder->leftJoin($entityName . '.postcode', $postCodeAlias); + } + + if ('postcode_name' === $field) { + $queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'name', $prefix, $field)); + + break; + } + + if ('postcode_code' === $field) { + $queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'code', $prefix, $field)); + + break; + } + + $countryAlias = sprintf('%scountry_t', $prefix); + + if (!in_array($countryAlias, $queryBuilder->getAllAliases(), true)) { + $queryBuilder->leftJoin(sprintf('%s.country', $postCodeAlias), $countryAlias); + } + + $queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $countryAlias, 'name', $prefix, $field)); + + break; + + case 'isNoAddress': + case 'confidential': + $queryBuilder->addSelect(sprintf('CASE WHEN %s.%s = \'TRUE\' THEN 1 ELSE 0 END AS %s%s', $entityName, $field, $prefix, $field)); + + break; + + case '_lat': + $queryBuilder->addSelect(sprintf('ST_Y(%s.point) AS %s%s', $entityName, $prefix, $field)); + + break; + + case '_lon': + $queryBuilder->addSelect(sprintf('ST_X(%s.point) AS %s%s', $entityName, $prefix, $field)); + + break; + + default: + throw new LogicException('This key is not supported: ' . $key); + } + } + } + } + } + /** * @param self::F_* $params * @@ -115,23 +202,11 @@ class ExportAddressHelper case 'extra': case 'flat': case 'floor': - return function ($value) use ($sanitizedKey, $translationPrefix) { - if ('_header' === $value) { - return $translationPrefix . $sanitizedKey; - } - - if (null === $value) { - return ''; - } - - $address = $this->addressRepository->find($value); - - return $this->propertyAccess->getValue($address, $sanitizedKey); - }; - case '_lat': case '_lon': - return function ($value) use ($sanitizedKey, $translationPrefix) { + case 'postcode_code': + case 'postcode_name': + return static function ($value) use ($sanitizedKey, $translationPrefix) { if ('_header' === $value) { return $translationPrefix . $sanitizedKey; } @@ -140,28 +215,25 @@ class ExportAddressHelper return ''; } - $address = $this->addressRepository->find($value); - $geom = $address->getPoint(); + return $value; + }; - if (null === $geom) { + case 'country': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp' . $key; + } + + if (null === $value) { return ''; } - switch ($sanitizedKey) { - case '_lat': - return $geom->getLat(); - - case '_lon': - return $geom->getLon(); - - default: - throw new LogicException('only _lat or _lon accepted, given: ' . $sanitizedKey); - } + return $this->translatableStringHelper->localize(json_decode($value, true)); }; case 'isNoAddress': case 'confidential': - return function ($value) use ($sanitizedKey, $translationPrefix) { + return static function ($value) use ($sanitizedKey, $translationPrefix) { if ('_header' === $value) { return $translationPrefix . $sanitizedKey; } @@ -170,9 +242,7 @@ class ExportAddressHelper return ''; } - $address = $this->addressRepository->find($value); - - switch ($val = $this->propertyAccess->getValue($address, $sanitizedKey)) { + switch ($value) { case null: return ''; @@ -187,21 +257,6 @@ class ExportAddressHelper } }; - case 'country': - return function ($value) use ($sanitizedKey, $translationPrefix) { - if ('_header' === $value) { - return $translationPrefix . $sanitizedKey; - } - - if (null === $value) { - return ''; - } - - $address = $this->addressRepository->find($value); - - return $this->translatableStringHelper->localize($address->getPostcode()->getCountry()->getName()); - }; - case '_as_string': return function ($value) use ($sanitizedKey, $translationPrefix) { if ('_header' === $value) { @@ -217,31 +272,6 @@ class ExportAddressHelper return $this->addressRender->renderString($address, []); }; - case 'postcode_code': - case 'postcode_name': - return function ($value) use ($sanitizedKey, $translationPrefix) { - if ('_header' === $value) { - return $translationPrefix . $sanitizedKey; - } - - if (null === $value) { - return ''; - } - - $address = $this->addressRepository->find($value); - - switch ($sanitizedKey) { - case 'postcode_code': - return $address->getPostcode()->getCode(); - - case 'postcode_name': - return $address->getPostcode()->getName(); - - default: - throw new LogicException('this key is not supported: ' . $sanitizedKey); - } - }; - default: throw new LogicException('this key is not supported: ' . $sanitizedKey); } diff --git a/src/Bundle/ChillMainBundle/Export/Helper/UserHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/UserHelper.php new file mode 100644 index 000000000..98c4c5579 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/Helper/UserHelper.php @@ -0,0 +1,43 @@ +userRender = $userRender; + $this->userRepository = $userRepository; + } + + public function getLabel($key, array $values, string $header): callable + { + return function ($value) use ($header) { + if ('_header' === $value) { + return $header; + } + + if (null === $value || null === $user = $this->userRepository->find($value)) { + return ''; + } + + return $this->userRender->renderString($user, []); + }; + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index 8c8744dfd..d07ee3639 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -38,7 +38,7 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder): void { - // TODO: Implement buildForm() method. + // Nothing to add here } public function getAllowedFormattersTypes(): array diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php new file mode 100644 index 000000000..28ad94bd3 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php @@ -0,0 +1,416 @@ +addressHelper = $addressHelper; + $this->dateTimeHelper = $dateTimeHelper; + $this->entityManager = $entityManager; + $this->personRender = $personRender; + $this->personRepository = $personRepository; + $this->socialIssueRender = $socialIssueRender; + $this->socialIssueRepository = $socialIssueRepository; + $this->thirdPartyRender = $thirdPartyRender; + $this->thirdPartyRepository = $thirdPartyRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->userHelper = $userHelper; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('calc_date', ChillDateType::class, [ + 'input' => 'datetime_immutable', + 'label' => 'export.list.acp.Date of calculation for associated elements', + 'help' => 'export.list.acp.The associated referree, localisation, and other elements will be valid at this date', + 'required' => true, + ]); + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_LIST]; + } + + public function getDescription() + { + return 'export.list.acp.Generate a list of accompanying periods, filtered on different parameters.'; + } + + public function getGroup(): string + { + return 'Exports of accompanying courses'; + } + + public function getLabels($key, array $values, $data) + { + if (substr($key, 0, strlen('address_fields')) === 'address_fields') { + return $this->addressHelper->getLabel($key, $values, $data, 'address_fields'); + } + + switch ($key) { + case 'stepSince': + case 'openingDate': + case 'closingDate': + case 'referrerSince': + case 'createdAt': + case 'updatedAt': + return $this->dateTimeHelper->getLabel('export.list.acp.' . $key); + + case 'origin': + case 'closingMotive': + case 'job': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value) { + return ''; + } + + return $this->translatableStringHelper->localize(json_decode($value, true)); + }; + + case 'locationPersonName': + case 'requestorPerson': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value || null === $person = $this->personRepository->find($value)) { + return ''; + } + + return $this->personRender->renderString($person, []); + }; + + case 'requestorThirdParty': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value || null === $thirdparty = $this->thirdPartyRepository->find($value)) { + return ''; + } + + return $this->thirdPartyRender->renderString($thirdparty, []); + }; + + case 'scopes': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value) { + return ''; + } + + return implode( + '|', + array_map( + fn ($s) => $this->translatableStringHelper->localize($s), + json_decode($value, true) + ) + ); + }; + + case 'socialIssues': + return function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value) { + return ''; + } + + return implode( + '|', + array_map( + fn ($s) => $this->socialIssueRender->renderString($this->socialIssueRepository->find($s), []), + json_decode($value, true) + ) + ); + }; + + default: + return static function ($value) use ($key) { + if ('_header' === $value) { + return 'export.list.acp.' . $key; + } + + if (null === $value) { + return ''; + } + + return $value; + }; + } + } + + public function getQueryKeys($data) + { + return array_merge( + self::FIELDS, + $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields') + ); + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR); + } + + public function getTitle() + { + return 'export.list.acp.List of accompanying periods'; + } + + public function getType() + { + return Declarations::PERSON_TYPE; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static function ($el) { + return $el['center']; + }, $acl); + + $qb = $this->entityManager->createQueryBuilder(); + + $qb + ->from(AccompanyingPeriod::class, 'acp') + ->andWhere('acp.step != :list_acp_step') + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part + JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) + WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + ' + ) + ) + ->setParameter('list_acp_step', AccompanyingPeriod::STEP_DRAFT) + ->setParameter('authorized_centers', $centers); + + $this->addSelectClauses($qb, $data['calc_date']); + + return $qb; + } + + public function requiredRole(): string + { + return PersonVoter::LISTS; + } + + public function supportsModifiers() + { + return [ + Declarations::ACP_TYPE, + ]; + } + + private function addSelectClauses(QueryBuilder $qb, DateTimeImmutable $calcDate): void + { + // add the regular fields + foreach (['id', 'openingDate', 'closingDate', 'confidential', 'emergency', 'intensity', 'createdAt', 'updatedAt'] as $field) { + $qb->addSelect(sprintf('acp.%s AS %s', $field, $field)); + } + + // add the field which are simple association + foreach (['origin' => 'label', 'closingMotive' => 'name', 'job' => 'label', 'createdBy' => 'label', 'updatedBy' => 'label', 'administrativeLocation' => 'name'] as $entity => $field) { + $qb + ->leftJoin(sprintf('acp.%s', $entity), "{$entity}_t") + ->addSelect(sprintf('%s_t.%s AS %s', $entity, $field, $entity)); + } + + // step at date + $qb + ->addSelect('stepHistory.step AS step') + ->addSelect('stepHistory.startDate AS stepSince') + ->leftJoin('acp.stepHistories', 'stepHistory') + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte('stepHistory.startDate', ':calcDate'), + $qb->expr()->orX($qb->expr()->isNull('stepHistory.endDate'), $qb->expr()->gt('stepHistory.endDate', ':calcDate')) + ) + ); + + // referree at date + $qb + ->addSelect('referrer_t.label AS referrer') + ->addSelect('userHistory.startDate AS referrerSince') + ->leftJoin('acp.userHistories', 'userHistory') + ->leftJoin('userHistory.user', 'referrer_t') + ->andWhere( + $qb->expr()->orX( + $qb->expr()->isNull('userHistory'), + $qb->expr()->andX( + $qb->expr()->lte('userHistory.startDate', ':calcDate'), + $qb->expr()->orX($qb->expr()->isNull('userHistory.endDate'), $qb->expr()->gt('userHistory.endDate', ':calcDate')) + ) + ) + ); + + // location of the acp + $qb + ->addSelect('CASE WHEN locationHistory.personLocation IS NOT NULL THEN 1 ELSE 0 END AS locationIsPerson') + ->addSelect('CASE WHEN locationHistory.personLocation IS NOT NULL THEN 0 ELSE 1 END AS locationIsTemp') + ->addSelect('IDENTITY(locationHistory.personLocation) AS locationPersonName') + ->addSelect('IDENTITY(locationHistory.personLocation) AS locationPersonId') + ->leftJoin('acp.locationHistories', 'locationHistory') + ->andWhere( + $qb->expr()->orX( + $qb->expr()->isNull('locationHistory'), + $qb->expr()->andX( + $qb->expr()->lte('locationHistory.startDate', ':calcDate'), + $qb->expr()->orX($qb->expr()->isNull('locationHistory.endDate'), $qb->expr()->gt('locationHistory.endDate', ':calcDate')) + ) + ) + ) + ->leftJoin(PersonHouseholdAddress::class, 'personAddress', Join::WITH, 'locationHistory.personLocation = personAddress.person') + ->andWhere( + $qb->expr()->orX( + $qb->expr()->isNull('personAddress'), + $qb->expr()->andX( + $qb->expr()->lte('personAddress.validFrom', ':calcDate'), + $qb->expr()->orX($qb->expr()->isNull('personAddress.validTo'), $qb->expr()->gt('personAddress.validTo', ':calcDate')) + ) + ) + ) + ->leftJoin(Address::class, 'acp_address', Join::WITH, 'COALESCE(IDENTITY(locationHistory.addressLocation), IDENTITY(personAddress.address)) = acp_address.id'); + + $this->addressHelper->addSelectClauses(ExportAddressHelper::F_ALL, $qb, 'acp_address', 'address_fields'); + + // requestor + $qb + ->addSelect('CASE WHEN acp.requestorPerson IS NULL THEN 1 ELSE 0 END AS isRequestorPerson') + ->addSelect('CASE WHEN acp.requestorPerson IS NULL THEN 0 ELSE 1 END AS isRequestorThirdParty') + ->addSelect('IDENTITY(acp.requestorPerson) AS requestorPersonId') + ->addSelect('IDENTITY(acp.requestorThirdParty) AS requestorThirdPartyId') + ->addSelect('IDENTITY(acp.requestorPerson) AS requestorPerson') + ->addSelect('IDENTITY(acp.requestorThirdParty) AS requestorThirdParty'); + + $qb + // scopes + ->addSelect('(SELECT AGGREGATE(scope.name) FROM ' . Scope::class . ' scope WHERE scope MEMBER OF acp.scopes) AS scopes') + // social issues + ->addSelect('(SELECT AGGREGATE(socialIssue.id) FROM ' . SocialIssue::class . ' socialIssue WHERE socialIssue MEMBER OF acp.socialIssues) AS socialIssues'); + + // add parameter + $qb->setParameter('calcDate', $calcDate); + } +} diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index eb746e122..d1a23a570 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -153,7 +153,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } if (substr($key, 0, strlen('address_fields')) === 'address_fields') { - $fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields')); + $fields = array_merge($fields, $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields')); continue; } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php index ce97ce662..534eaecc6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php @@ -17,6 +17,7 @@ use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; @@ -121,7 +122,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac } if (substr($key, 0, strlen('address_fields')) === 'address_fields') { - $fields = array_merge($fields, $this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields')); + $fields = array_merge($fields, $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields')); continue; } @@ -173,6 +174,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac $qb->from(Person::class, 'person') ->join('person.accompanyingPeriodParticipations', 'acppart') ->join('acppart.accompanyingPeriod', 'acp') + ->andWhere($qb->expr()->neq('acp.step', "'" . AccompanyingPeriod::STEP_DRAFT . "'")) ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php index 69f797c3d..de8870674 100644 --- a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php +++ b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Helper; use Chill\MainBundle\Export\Helper\ExportAddressHelper; +use Chill\MainBundle\Repository\CenterRepositoryInterface; use Chill\MainBundle\Repository\CivilityRepositoryInterface; use Chill\MainBundle\Repository\CountryRepository; use Chill\MainBundle\Repository\LanguageRepositoryInterface; @@ -72,16 +73,10 @@ class ListPersonHelper 'lifecycleUpdate', ]; - public const HELPER_ATTRIBUTES = ExportAddressHelper::F_ATTRIBUTES | - ExportAddressHelper::F_BUILDING | - ExportAddressHelper::F_COUNTRY | - ExportAddressHelper::F_GEOM | - ExportAddressHelper::F_POSTAL_CODE | - ExportAddressHelper::F_STREET | - ExportAddressHelper::F_AS_STRING; - private ExportAddressHelper $addressHelper; + private CenterRepositoryInterface $centerRepository; + private CivilityRepositoryInterface $civilityRepository; private CountryRepository $countryRepository; @@ -98,6 +93,7 @@ class ListPersonHelper public function __construct( ExportAddressHelper $addressHelper, + CenterRepositoryInterface $centerRepository, CivilityRepositoryInterface $civilityRepository, CountryRepository $countryRepository, LanguageRepositoryInterface $languageRepository, @@ -107,6 +103,7 @@ class ListPersonHelper UserRepositoryInterface $userRepository ) { $this->addressHelper = $addressHelper; + $this->centerRepository = $centerRepository; $this->civilityRepository = $civilityRepository; $this->countryRepository = $countryRepository; $this->languageRepository = $languageRepository; @@ -134,12 +131,9 @@ class ListPersonHelper break; case 'address_fields': - foreach ($this->addressHelper->getKeys(ListPersonHelper::HELPER_ATTRIBUTES, 'address_fields') as $key) { - $qb - ->addSelect(sprintf('IDENTITY(personHouseholdAddress.address) AS %s', $key)); - } - $this->addCurrentAddressAt($qb, $computedDate); + $qb->leftJoin('personHouseholdAddress.address', 'personAddress'); + $this->addressHelper->addSelectClauses(ExportAddressHelper::F_ALL, $qb, 'personAddress', 'address_fields'); break; @@ -154,7 +148,10 @@ class ListPersonHelper } if (in_array('address_fields', $fields, true)) { - $qb->addGroupBy('address_fieldsid'); + $qb + ->addGroupBy('address_fieldsid') + ->addGroupBy('address_fieldscountry_t.id') + ->addGroupBy('address_fieldspostcode_t.id'); } if (in_array('household_id', $fields, true)) { @@ -234,7 +231,7 @@ class ListPersonHelper return array_merge( self::FIELDS, ['createdAt', 'createdBy', 'updatedAt', 'updatedBy'], - $this->addressHelper->getKeys(self::HELPER_ATTRIBUTES, 'address_fields') + $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields') ); } @@ -245,6 +242,19 @@ class ListPersonHelper } switch ($key) { + case 'center': + return function ($value) use ($key) { + if ('_header' === $value) { + return $this->translator->trans($key); + } + + if (null === $value || null === $center = $this->centerRepository->find($value)) { + return ''; + } + + return $center->getName(); + }; + case 'birthdate': case 'deathdate': case 'maritalStatusDate': @@ -413,7 +423,7 @@ class ListPersonHelper ->leftJoin('person.householdAddresses', 'personHouseholdAddress') ->andWhere( $qb->expr()->orX( - // no address at this time + // no address at this time $qb->expr()->isNull('personHouseholdAddress'), // there is one address... $qb->expr()->andX( diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index b9030ec62..b2b182c5b 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -27,6 +27,12 @@ services: tags: - { name: chill.export, alias: list_person_with_acp } + Chill\PersonBundle\Export\Export\ListAccompanyingPeriod: + autowire: true + autoconfigure: true + tags: + - { name: chill.export, alias: list_acp } + chill.person.export.list_person.duplicate: class: Chill\PersonBundle\Export\Export\ListPersonDuplicate arguments: diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 5f43608ce..319231489 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1020,8 +1020,48 @@ export: by_referrer: Computation date for referrer: Date à laquelle le référent était actif list: - person_with_acp.List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement - Create a list of people having an accompaying periods, according to various filters.: Génère une liste des personnes ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager + person_with_acp: + List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement + Create a list of people having an accompaying periods, according to various filters.: Génère une liste des personnes ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager + acp: + List of accompanying periods: Liste de périodes d'accompagnements + Generate a list of accompanying periods, filtered on different parameters.: Génère une liste des périodes d'accompagnement, filtrée sur différents paramètres. + Date of calculation for associated elements: Date de calcul des éléments associés + The associated referree, localisation, and other elements will be valid at this date: Les éléments associés, comme la localisation, le référent et d'autres éléments seront valides à cette date + id: Identifiant du parcours + openingDate: Date d'ouverture du parcours + closingDate: Date de fermeture du parcours + confidential: Confidentiel + emergency: Urgent + intensity: Intensité + createdAt: Créé le + updatedAt: Dernière mise à jour le + acpOrigin: Origine du parcours + acpClosingMotive: Motif de fermeture + acpJob: Métier du parcours + createdBy: Créé par + updatedBy: Dernière modification par + administrativeLocation: Location administrative + step: Etape + stepSince: Dernière modification de l'étape + referrer: Référent + referrerSince: Référent depuis le + locationIsPerson: Parcours localisé auprès d'un usager concerné + locationIsTemp: Parcours avec une localisation temporaire + acpLocationPersonName: Usager auprès duquel le parcours est localisé + locationPersonId: Identifiant de l'usager auprès duquel le parcours est localisé + acpaddress_fieldscountry: Pays de l'adresse + isRequestorPerson: Le demandeur est-il un usager ? + isRequestorThirdParty: Le demandeur est-il un tiers ? + requestorPersonId: Identifiant du demandeur personne + requestorThirdPartyId: Identifiant du tiers + acprequestorPerson: Nom du demandeur personne + acprequestorThirdPaty: Nom du demandeur tiers + scopes: Services + socialIssues: Problématiques sociales + + + social_action: and children: et dérivés From c331f9420174cae5e17204410e27e1d5d638dd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 31 Oct 2022 17:53:25 +0100 Subject: [PATCH 25/99] fix cs --- .../ChillActivityBundle/Export/Filter/UsersJobFilter.php | 4 ++-- .../ByHouseholdCompositionAggregator.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php index dcdacd84a..b52ef441c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php @@ -39,9 +39,9 @@ class UsersJobFilter implements FilterInterface $qb ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . Activity::class . ' activity_users_job_filter_act + 'SELECT 1 FROM ' . Activity::class . ' activity_users_job_filter_act JOIN activity_users_job_filter_act.users users WHERE users.userJob IN (:activity_users_job_filter_jobs) AND activity_users_job_filter_act = activity ' - ) + ) ) ->setParameter('activity_users_job_filter_jobs', $data['jobs']); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php index e96c8a228..f299762e6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php @@ -18,6 +18,7 @@ use Chill\PersonBundle\Entity\Household\HouseholdComposition; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface; +use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -96,7 +97,7 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface $builder->add('date_calc', ChillDateType::class, [ 'label' => 'export.aggregator.course.by_household_composition.Calc date', 'input_format' => 'datetime_immutable', - 'data' => new \DateTimeImmutable('now'), + 'data' => new DateTimeImmutable('now'), ]); } From afa6dfd77c92fd1c6cf8f3a3aa6bbc72595e01d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 31 Oct 2022 18:00:41 +0100 Subject: [PATCH 26/99] fix psalm errors --- .../ChillMainBundle/Export/Helper/ExportAddressHelper.php | 2 +- .../ChillMainBundle/Tests/Export/ExportManagerTest.php | 6 ++++-- src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php | 2 +- .../Export/Export/ListPersonWithAccompanyingPeriod.php | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 41443e3d8..268abc3ea 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -253,7 +253,7 @@ class ExportAddressHelper return 0; default: - throw new LogicException('this value is not supported for ' . $sanitizedKey . ': ' . $val); + throw new LogicException('this value is not supported for ' . $sanitizedKey . ': ' . $value); } }; diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php index b3f5eac85..701b3d14e 100644 --- a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php @@ -680,10 +680,12 @@ final class ExportManagerTest extends KernelTestCase return new ExportManager( $logger ?? self::$container->get('logger'), - $em ?? self::$container->get('doctrine.orm.entity_manager'), $authorizationChecker ?? self::$container->get('security.authorization_checker'), $authorizationHelper ?? self::$container->get('chill.main.security.authorization.helper'), - $tokenStorage + $tokenStorage, + [], + [], + [] ); } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index d1a23a570..549fe1c4d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -187,7 +187,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } /** - * @param array{fields: string[], address_date: DateTimeImmutable} $data + * param array{fields: string[], address_date: DateTimeImmutable} $data */ public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php index 534eaecc6..7ddc6c9d3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php @@ -155,7 +155,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac } /** - * @param array{fields: string[], address_date: DateTimeImmutable} $data + * param array{fields: string[], address_date: DateTimeImmutable} $data */ public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { From acc9523ff5edff313bb19bfb1f300ef9487e5ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 31 Oct 2022 18:22:01 +0100 Subject: [PATCH 27/99] DX: repairs code style, and psalm types --- phpstan-types.neon | 20 ------------------- .../Export/Helper/ExportAddressHelper.php | 7 +------ .../Export/Export/ListPerson.php | 2 +- .../ListPersonWithAccompanyingPeriod.php | 2 +- 4 files changed, 3 insertions(+), 28 deletions(-) diff --git a/phpstan-types.neon b/phpstan-types.neon index bf2ece912..1aae06880 100644 --- a/phpstan-types.neon +++ b/phpstan-types.neon @@ -10,16 +10,6 @@ parameters: count: 1 path: src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php - - - message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getDescription\\(\\) should return string but return statement is missing\\.$#" - count: 1 - path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php - - - - message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getTitle\\(\\) should return string but return statement is missing\\.$#" - count: 1 - path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 @@ -330,16 +320,6 @@ parameters: count: 6 path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 1 - path: src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php - - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 1 - path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 268abc3ea..2f9a270ff 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -58,7 +58,7 @@ class ExportAddressHelper 'country' => ['country'], 'postal_code' => ['postcode_code', 'postcode_name'], 'street' => ['street', 'streetNumber'], - 'building' => ['buildingName', 'corridor', 'distribution', 'extra', 'flat', 'floor'], + 'building' => ['buildingName', 'corridor', 'distribution', 'extra', 'flat', 'floor', 'steps'], 'string' => ['_as_string'], 'attributes' => ['isNoAddress', 'confidential', 'id'], 'geom' => ['_lat', '_lon'], @@ -97,7 +97,6 @@ class ExportAddressHelper case 'street': case 'streetNumber': - case 'building': case 'floor': case 'corridor': case 'steps': @@ -238,10 +237,6 @@ class ExportAddressHelper return $translationPrefix . $sanitizedKey; } - if (null === $value) { - return ''; - } - switch ($value) { case null: return ''; diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 549fe1c4d..acaeb498c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -187,7 +187,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } /** - * param array{fields: string[], address_date: DateTimeImmutable} $data + * param array{fields: string[], address_date: DateTimeImmutable} $data. */ public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php index 7ddc6c9d3..bab67fb39 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php @@ -155,7 +155,7 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac } /** - * param array{fields: string[], address_date: DateTimeImmutable} $data + * param array{fields: string[], address_date: DateTimeImmutable} $data. */ public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { From 8d4ec5d6756c049de96017e8f88f6af56bc0e9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 11:12:55 +0100 Subject: [PATCH 28/99] fix code style --- .../ACPAggregators/ByActivityNumberAggregator.php | 4 ++-- .../Export/Aggregator/SentReceivedAggregator.php | 10 ++++++---- .../Export/Filter/ACPFilters/HasNoActivityFilter.php | 7 ++++--- .../Export/Aggregator/ByActivityTypeAggregator.php | 4 ++-- .../src/Export/Declarations.php | 2 +- .../src/Export/Export/CountAsideActivity.php | 6 +----- .../src/Export/Filter/ByActivityTypeFilter.php | 2 +- .../src/Export/Filter/ByDateFilter.php | 2 +- .../ByActionNumberAggregator.php | 4 ++-- .../CreatorJobAggregator.php | 4 ++-- .../EvaluationAggregators/ByEndDateAggregator.php | 4 ++-- .../EvaluationAggregators/ByMaxDateAggregator.php | 4 ++-- .../EvaluationAggregators/ByStartDateAggregator.php | 4 ++-- .../HavingEndDateAggregator.php | 9 +++++---- .../CurrentActionAggregator.php | 10 ++++++---- .../AccompanyingCourseFilters/CreatorFilter.php | 2 +- .../AccompanyingCourseFilters/CreatorJobFilter.php | 2 +- .../AccompanyingCourseFilters/HasNoActionFilter.php | 3 ++- .../HasNoReferrerFilter.php | 12 ++++++------ .../HasTemporaryLocationFilter.php | 2 +- .../Filter/EvaluationFilters/ByEndDateFilter.php | 4 ++-- .../Filter/EvaluationFilters/ByStartDateFilter.php | 4 ++-- .../EvaluationFilters/CurrentEvaluationsFilter.php | 2 +- .../Filter/SocialWorkFilters/CurrentActionFilter.php | 2 +- 24 files changed, 56 insertions(+), 53 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php index 44a3fd8f0..de35f75cc 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByActivityNumberAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index b5300834c..2a6dec7f7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -11,9 +11,10 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; -use Chill\MainBundle\Export\AggregatorInterface; use Chill\ActivityBundle\Export\Declarations; +use Chill\MainBundle\Export\AggregatorInterface; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class SentReceivedAggregator implements AggregatorInterface @@ -41,10 +42,11 @@ class SentReceivedAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case 'sent': return 'is sent'; @@ -53,7 +55,7 @@ class SentReceivedAggregator implements AggregatorInterface return 'is received'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } }; } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php index 13aaf475a..508644a07 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -14,9 +14,10 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\Query\Expr; +use function in_array; class HasNoActivityFilter implements FilterInterface { @@ -36,7 +37,7 @@ class HasNoActivityFilter implements FilterInterface //TODO check this: ->andWhere(' NOT EXISTS ( - SELECT 1 FROM '. Activity::class .' activity + SELECT 1 FROM ' . Activity::class . ' activity WHERE activity.accompanyingPeriod = acp ) '); @@ -61,4 +62,4 @@ class HasNoActivityFilter implements FilterInterface { return 'Filter acp which has no activity'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index bbbdb6284..2104db81e 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByActivityTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php index 0262516aa..925169a68 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Declarations.php @@ -17,4 +17,4 @@ namespace ChillAsideActivityBundle\Export; abstract class Declarations { public const ASIDE_ACTIVITY_TYPE = 'aside_activity'; -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index 7af39568e..01b6a5204 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -16,9 +16,9 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use ChillAsideActivityBundle\Export\Declarations; -use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\Query; use LogicException; +use Symfony\Component\Form\FormBuilderInterface; class CountAsideActivity implements ExportInterface, GroupedExportInterface { @@ -105,7 +105,3 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface return []; } } - - - - diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 60ca914b2..46d84c064 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -52,4 +52,4 @@ class ByActivityTypeFilter implements FilterInterface { return 'Filter by aside activity type'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index dc6b89662..ad876571e 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -52,4 +52,4 @@ class ByDateFilter implements FilterInterface { return 'Filter by aside activity date'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php index 3c16aa161..0f51b6feb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByActionNumberAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index 1449091e7..c473bf7a1 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class CreatorJobAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php index 9c90c8dd3..40b035a02 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByEndDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php index ded9fb685..36ab0f50b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByMaxDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index 121171d8c..e64245d53 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -41,7 +41,7 @@ class ByStartDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php index 8def8cf88..af801b74d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Aggregator\EvaluationAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class HavingEndDateAggregator implements AggregatorInterface @@ -45,10 +46,11 @@ class HavingEndDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case true: return 'enddate is specified'; @@ -57,9 +59,8 @@ class HavingEndDateAggregator implements AggregatorInterface return 'enddate is not specified'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } - }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index d9120d121..a77838167 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -/** +/* * Chill is a software for social workers * * For the full copyright and license information, please view @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; class CurrentActionAggregator implements AggregatorInterface @@ -27,7 +28,7 @@ class CurrentActionAggregator implements AggregatorInterface { $qb ->addSelect(' - (CASE true WHEN acpw.startDate IS NULL ELSE false END) + (CASE true WHEN acpw.startDate IS NULL ELSE false END) AS acpw_current_action_aggregator ') ->addGroupBy('acpw_current_action_aggregator'); @@ -45,10 +46,11 @@ class CurrentActionAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { + return static function ($value): string { if ('_header' === $value) { return ''; } + switch ($value) { case true: return 'Current action'; @@ -57,7 +59,7 @@ class CurrentActionAggregator implements AggregatorInterface return 'Not current action'; default: - throw new \LogicException(sprintf('The value %s is not valid', $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php index 7dd78d0b4..c7e110f62 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -52,4 +52,4 @@ class CreatorFilter implements FilterInterface { return 'Filter by creator'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index 021d2227c..6f094fe97 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -52,4 +52,4 @@ class CreatorJobFilter implements FilterInterface { return 'Filter by creator job'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php index a26628e95..771b8d063 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use function in_array; class HasNoActionFilter implements FilterInterface { @@ -51,4 +52,4 @@ class HasNoActionFilter implements FilterInterface { return 'Filter by which has no action'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index c37d423f8..b18bcd1de 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -15,10 +15,10 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class HasNoReferrerFilter implements FilterInterface { @@ -32,12 +32,12 @@ class HasNoReferrerFilter implements FilterInterface $qb ->andWhere(' NOT EXISTS ( - SELECT 1 FROM '. UserHistory::class .' uh - WHERE uh.startDate < :date + SELECT 1 FROM ' . UserHistory::class . ' uh + WHERE uh.startDate < :date AND ( - uh.endDate IS NULL + uh.endDate IS NULL or uh.endDate > :date - ) + ) AND uh.accompanyingPeriod = acp ) ') @@ -69,4 +69,4 @@ class HasNoReferrerFilter implements FilterInterface { return 'Filter by which has no referrer'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 18a6c3918..85d8d93b6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -52,4 +52,4 @@ class HasTemporaryLocationFilter implements FilterInterface { return 'Filter by temporary location'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index d40170447..5c509d50c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -14,10 +14,10 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class ByEndDateFilter implements FilterInterface { @@ -64,4 +64,4 @@ class ByEndDateFilter implements FilterInterface { return 'Filter by end date evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index afa3c212a..e21a1ea68 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -14,10 +14,10 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use DateTime; class ByStartDateFilter implements FilterInterface { @@ -64,4 +64,4 @@ class ByStartDateFilter implements FilterInterface { return 'Filter by start date evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php index 293e551f1..50c95600e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -47,4 +47,4 @@ class CurrentEvaluationsFilter implements FilterInterface { return 'Filter by current evaluations'; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php index ecbe6086a..cbf958182 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -47,4 +47,4 @@ class CurrentActionFilter implements FilterInterface { return 'Filter by current actions'; } -} \ No newline at end of file +} From 355436aa8242b0a09b1bf7666e726c6b7218a9a3 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 11:15:54 +0100 Subject: [PATCH 29/99] acp creator filter --- .../CreatorFilter.php | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php index c7e110f62..1ac6d5390 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -12,9 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use function in_array; class CreatorFilter implements FilterInterface { @@ -25,11 +28,21 @@ class CreatorFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + if (!in_array('acp_creator', $qb->getAllAliases(), true)) { + $qb->join('acp.createdBy', 'acp_creator'); + } + + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->in('acp_creator', ':creators'); + + if ($where instanceof Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('creators', $data['accepted_creators']); } public function applyOn(): string @@ -39,13 +52,24 @@ class CreatorFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + $builder + ->add('accepted_creators', PickUserDynamicType::class, [ + 'multiple' => true, + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + $creators = []; + + foreach ($data['accepted_creators'] as $c) { + $creators[] = $c; + } + + return [ + 'Filtered by creator: only %creators%', [ + '%creators%' => implode(', ', $creators), + ], ]; } public function getTitle(): string From edd1557f35e609b728db5c047db00a6ec553bdbf Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 11:32:55 +0100 Subject: [PATCH 30/99] comment out builder method --- .../src/Export/Filter/ByActivityTypeFilter.php | 2 +- .../ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php | 2 +- .../AccompanyingCourseFilters/HasTemporaryLocationFilter.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 4f256538d..354bd9f3c 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -39,7 +39,7 @@ class ByActivityTypeFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //$builder->add(); } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index d8fec664a..5a63e8e94 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -39,7 +39,7 @@ class ByDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //$builder->add(); } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 85d8d93b6..b674f1881 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -39,7 +39,7 @@ class HasTemporaryLocationFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + //$builder->add(); } public function describeAction($data, $format = 'string'): array From 749facb9b0e226c7e8afbfe354f31b5ee8b28160 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 11:55:36 +0100 Subject: [PATCH 31/99] creator job filter --- .../CreatorJobFilter.php | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index 6f094fe97..71fe3250f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -11,13 +11,26 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; +use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; +use function in_array; class CreatorJobFilter implements FilterInterface { + private TranslatableStringHelper $translatableStringHelper; + + public function __construct( + TranslatableStringHelper $translatableStringHelper + ) { + $this->translatableStringHelper = $translatableStringHelper; + } + public function addRole(): ?string { return null; @@ -25,11 +38,21 @@ class CreatorJobFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + if (!in_array('acp_creator', $qb->getAllAliases(), true)) { + $qb->join('acp.createdBy', 'acp_creator'); + } + + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->in('acp_creator.userJob', ':creator_job'); + + if ($where instanceof Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('creator_job', $data['creator_job']); } public function applyOn(): string @@ -39,12 +62,30 @@ class CreatorJobFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add(); + $builder->add('creator_job', EntityType::class, [ + 'class' => UserJob::class, + 'choice_label' => function (UserJob $j) { + return $this->translatableStringHelper->localize( + $j->getLabel() + ); + }, + 'multiple' => true, + 'expanded' => true, + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ + $creatorJobs = []; + + foreach ($data['creator_job'] as $j) { + $creatorJobs[] = $this->translatableStringHelper->localize( + $j->getLabel() + ); + } + + return ['Filtered by creator job: only %jobs%', [ + '%jobs%' => implode(', ', $creatorJobs), ]]; } From 32cdf56fbd0a5c6933a70333c5a0917cfc52742c Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 12:00:29 +0100 Subject: [PATCH 32/99] add translations creator filters --- src/Bundle/ChillPersonBundle/translations/messages.fr.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 319231489..134a97414 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -572,9 +572,11 @@ Filter by which has no action: Filtrer les parcours qui n’ont pas d’actions Filtered acp which has no actions: Filtré les parcours qui n'ont pas d'actions Group by number of actions: Grouper les parcours par nombre d’actions Filter by creator: Filtrer les parcours par créateur +'Filtered by creator: only %creators%': 'Filtré par créateur: uniquement %creators%' Filter by creator job: Filtrer les parcours par métier du créateur +'Filtered by creator job: only %jobs%': 'Filtré par métier du créateur: uniquement %jobs%' Group by creator job: Grouper les parcours par métier du créateur - + Filter by current actions: Filtrer les actions en cours Filtered by current action: Filtré les actions en cours Group by current actions: Grouper les actions en cours From 17a7b053cf821f39c95a5baa75decfa568e8c811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 11:32:21 +0100 Subject: [PATCH 33/99] DX: remove unused variable --- src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php index 9da2f4ffd..90743d1ba 100644 --- a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php @@ -54,8 +54,6 @@ class UserMenuBuilder implements LocalMenuBuilderInterface public function buildMenu($menuId, MenuItem $menu, array $parameters) { - $user = $this->tokenStorage->getToken()->getUser(); - if ($this->authorizationChecker->isGranted('ROLE_USER')) { $menu->addChild('My calendar list', [ 'route' => 'chill_calendar_calendar_list', From e46b285d3e594c0fd23a14c571641be3175b2632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 11:34:50 +0100 Subject: [PATCH 34/99] Fixed: handle null value in SentReceivedAggregator --- .../Export/Aggregator/SentReceivedAggregator.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index 2a6dec7f7..24000096f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -48,6 +48,9 @@ class SentReceivedAggregator implements AggregatorInterface } switch ($value) { + case null: + return ''; + case 'sent': return 'is sent'; From be75cdce550e9aa55b218fb29ee7db04330d4b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 12:55:10 +0100 Subject: [PATCH 35/99] Feature: [export] Finalize HasTemporaryLocation filter on accompanying course --- .../HasTemporaryLocationFilter.php | 64 +++++++++++++++++-- .../translations/messages.fr.yml | 6 +- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index b674f1881..2ae1ad2a0 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -12,8 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; +use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; class HasTemporaryLocationFilter implements FilterInterface @@ -26,10 +30,25 @@ class HasTemporaryLocationFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + ->join('acp.locationHistories', 'acp_having_temporarily_location') + ->andWhere('acp_having_temporarily_location.startDate <= :acp_having_temporarily_location_date + AND (acp_having_temporarily_location.endDate IS NULL OR acp_having_temporarily_location.endDate > :acp_having_temporarily_location_date)') + ->setParameter('acp_having_temporarily_location_date', $data['calc_date']); + + switch ($data['having_temporarily']) { + case true: + $qb->andWhere('acp_having_temporarily_location.addressLocation IS NOT NULL'); + + break; + + case false: + $qb->andWhere('acp_having_temporarily_location.personLocation IS NOT NULL'); + + break; + + default: + throw new LogicException('value not supported'); + } } public function applyOn(): string @@ -39,13 +58,44 @@ class HasTemporaryLocationFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - //$builder->add(); + $builder + ->add('having_temporarily', ChoiceType::class, [ + 'choices' => [ + 'export.filter.course.having_temporarily.Having a temporarily location' => true, + 'export.filter.course.having_temporarily.Having a person\'s location' => false, + ], + 'choice_label' => static function ($choice) { + switch ($choice) { + case true: + return 'export.filter.course.having_temporarily.Having a temporarily location'; + + case false: + return 'export.filter.course.having_temporarily.Having a person\'s location'; + + default: + throw new LogicException('this choice is not supported'); + } + }, + ]) + ->add('calc_date', ChillDateType::class, [ + 'label' => 'export.filter.course.having_temporarily.Calculation date', + 'input' => 'datetime_immutable', + 'data' => new DateTimeImmutable(), + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ - ]]; + switch ($data['having_temporarily']) { + case true: + return ['export.filter.course.having_temporarily.Having a temporarily location', []]; + + case false: + return ['export.filter.course.having_temporarily.Having a person\'s location', []]; + + default: + throw new LogicException('value not supported'); + } } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 319231489..a48d5ea46 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -574,7 +574,7 @@ Group by number of actions: Grouper les parcours par nombre d’actions Filter by creator: Filtrer les parcours par créateur Filter by creator job: Filtrer les parcours par métier du créateur Group by creator job: Grouper les parcours par métier du créateur - + Filter by current actions: Filtrer les actions en cours Filtered by current action: Filtré les actions en cours Group by current actions: Grouper les actions en cours @@ -1019,6 +1019,10 @@ export: Computation date for referrer: Date à laquelle le référent était actif by_referrer: Computation date for referrer: Date à laquelle le référent était actif + having_temporarily: + Having a temporarily location: Ayant une localisation temporaire + Having a person's location: Ayant une localisation auprès d'un usager + Calculation date: Date de la localisation list: person_with_acp: List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement From be215bd1356fa511ae6f3686df3aed24d8162803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 13:05:12 +0100 Subject: [PATCH 36/99] DX: simplify creatorJobFilter --- .../CreatorJobFilter.php | 25 ++++++++----------- .../translations/messages.fr.yml | 2 ++ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index 71fe3250f..c8b7ccc55 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -13,9 +13,9 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Repository\UserJobRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; @@ -25,10 +25,14 @@ class CreatorJobFilter implements FilterInterface { private TranslatableStringHelper $translatableStringHelper; + private UserJobRepositoryInterface $userJobRepository; + public function __construct( - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + UserJobRepositoryInterface $userJobRepository ) { $this->translatableStringHelper = $translatableStringHelper; + $this->userJobRepository = $userJobRepository; } public function addRole(): ?string @@ -42,17 +46,9 @@ class CreatorJobFilter implements FilterInterface $qb->join('acp.createdBy', 'acp_creator'); } - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->in('acp_creator.userJob', ':creator_job'); - - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('creator_job', $data['creator_job']); + $qb + ->andWhere($qb->expr()->in('acp_creator.userJob', ':creator_job')) + ->setParameter('creator_job', $data['creator_job']); } public function applyOn(): string @@ -64,6 +60,7 @@ class CreatorJobFilter implements FilterInterface { $builder->add('creator_job', EntityType::class, [ 'class' => UserJob::class, + 'choices' => $this->userJobRepository->findAllActive(), 'choice_label' => function (UserJob $j) { return $this->translatableStringHelper->localize( $j->getLabel() @@ -84,7 +81,7 @@ class CreatorJobFilter implements FilterInterface ); } - return ['Filtered by creator job: only %jobs%', [ + return ['export.filter.course.creator_job.Filtered by creator job: only %jobs%', [ '%jobs%' => implode(', ', $creatorJobs), ]]; } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index a48d5ea46..3821253ed 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1023,6 +1023,8 @@ export: Having a temporarily location: Ayant une localisation temporaire Having a person's location: Ayant une localisation auprès d'un usager Calculation date: Date de la localisation + creator_job: + 'Filtered by creator job: only %jobs%': 'Filtré par métier du créateur: seulement %jobs%' list: person_with_acp: List peoples having an accompanying period: Liste des personnes ayant un parcours d'accompagnement From 50e2f4a147eef0d62a478c39353e40490fdcffc8 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 13:14:38 +0100 Subject: [PATCH 37/99] setup aside activity export --- .../DependencyInjection/ChillAsideActivityExtension.php | 1 + .../src/config/services/export.yaml | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml diff --git a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php index e81b887c0..ef6c5d69b 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php @@ -30,6 +30,7 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte $loader->load('services.yaml'); $loader->load('services/form.yaml'); $loader->load('services/menu.yaml'); + $loader->load('services/export.yaml'); } public function prepend(ContainerBuilder $container) diff --git a/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml b/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml new file mode 100644 index 000000000..579791d41 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml @@ -0,0 +1,9 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + ## Indicators + Chill\AsideActivityBundle\Export\Export\CountAsideActivity: + tags: + - { name: chill.export, alias: 'count_aside_activity' } From 094a912e427b13ebb05356234dce2c88b1139528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 13:14:48 +0100 Subject: [PATCH 38/99] Fixed: fix date's type in DateType input, and prevent collision on parameter name --- .../AccompanyingCourseFilters/HasNoReferrerFilter.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index b18bcd1de..303c789af 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -15,7 +15,7 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Export\Declarations; -use DateTime; +use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -33,15 +33,15 @@ class HasNoReferrerFilter implements FilterInterface ->andWhere(' NOT EXISTS ( SELECT 1 FROM ' . UserHistory::class . ' uh - WHERE uh.startDate < :date + WHERE uh.startDate <= :has_no_referrer_filter_date AND ( uh.endDate IS NULL - or uh.endDate > :date + or uh.endDate > :has_no_referrer_filter_date ) AND uh.accompanyingPeriod = acp ) ') - ->setParameter('date', $data['calc_date'], Types::DATE_IMMUTABLE); + ->setParameter('has_no_referrer_filter_date', $data['calc_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -54,7 +54,8 @@ class HasNoReferrerFilter implements FilterInterface $builder ->add('calc_date', ChillDateType::class, [ 'label' => 'Has no referrer on this date', - 'data' => new DateTime(), + 'data' => new DateTimeImmutable(), + 'input' => 'datetime_immutable', ]); } From 5acf2a198680c2f3faa79d669853af5c5751952d Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 13:17:03 +0100 Subject: [PATCH 39/99] creator job aggregator --- .../CreatorJobAggregator.php | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index c473bf7a1..3bae64fec 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -12,12 +12,27 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; +use Chill\MainBundle\Repository\UserJobRepository; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use function in_array; class CreatorJobAggregator implements AggregatorInterface { + private UserJobRepository $jobRepository; + + private TranslatableStringHelper $translatableStringHelper; + + public function __construct( + UserJobRepository $jobRepository, + TranslatableStringHelper $translatableStringHelper + ) { + $this->jobRepository = $jobRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + public function addRole(): ?string { return null; @@ -25,7 +40,11 @@ class CreatorJobAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS acp_creator_job_aggregator') + if (!in_array('acp_creator', $qb->getAllAliases(), true)) { + $qb->leftJoin('acp.createdBy', 'acp_creator'); + } + + $qb->addSelect('IDENTITY(acp_creator.userJob) AS acp_creator_job_aggregator') ->addGroupBy('acp_creator_job_aggregator'); } @@ -41,10 +60,20 @@ class CreatorJobAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return static function ($value): string { + return function ($value): string { if ('_header' === $value) { + return 'Job'; + } + + if (null === $value) { return ''; } + + $j = $this->jobRepository->find($value); + + return $this->translatableStringHelper->localize( + $j->getLabel() + ); }; } From 84e5be6a600f0a549a866c0f7273c0523f671521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 13:21:26 +0100 Subject: [PATCH 40/99] DX: review for hasNoActivityFilter --- .../Export/Filter/ACPFilters/HasNoActivityFilter.php | 10 +--------- .../ChillActivityBundle/translations/messages.fr.yml | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php index 508644a07..570f42ae0 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -14,10 +14,8 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Export\Declarations; -use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class HasNoActivityFilter implements FilterInterface { @@ -28,13 +26,7 @@ class HasNoActivityFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - if (!in_array('activity', $qb->getAllAliases(), true)) { - $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp'); - } - $qb - //->andWhere('COUNT(acp.activities) IS NULL') - //TODO check this: ->andWhere(' NOT EXISTS ( SELECT 1 FROM ' . Activity::class . ' activity @@ -55,7 +47,7 @@ class HasNoActivityFilter implements FilterInterface public function describeAction($data, $format = 'string'): array { - return ['Filtered acp which has no activities']; + return ['Filtered acp which has no activities', []]; } public function getTitle(): string diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index e3fcfd2b2..1d5e7f1f2 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -278,7 +278,7 @@ Filter activity by userscope: Filtrer les activités par service du créateur Accepted userscope: Services Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activité -Filtered acp which has no activities: Filtrés les parcours qui n'ont pas d'activités +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é Group activity by sentreceived: Grouper les activités par envoyé / reçu From 24873f0cc29092ff7a8f7f35145c85ac6cc9bfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 13:33:33 +0100 Subject: [PATCH 41/99] Feature: [export] add aggregator by "number of activity" for acp --- .../ByActivityNumberAggregator.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php index de35f75cc..5c6656009 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators; +use Chill\ActivityBundle\Entity\Activity; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -23,9 +24,10 @@ class ByActivityNumberAggregator implements AggregatorInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { - $qb->addSelect('AS activity_by_number_aggregator') + $qb + ->addSelect('(SELECT COUNT(activity.id) FROM ' . Activity::class . ' activity WHERE activity.accompanyingPeriod = acp) AS activity_by_number_aggregator') ->addGroupBy('activity_by_number_aggregator'); } @@ -34,17 +36,23 @@ class ByActivityNumberAggregator implements AggregatorInterface return Declarations::ACP_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { // No form needed } public function getLabels($key, array $values, $data) { - return static function ($value): string { + return static function ($value) { if ('_header' === $value) { return ''; } + + if (null === $value) { + return ''; + } + + return $value; }; } From 51ac4e0938038acf775e10de292438700a5eba10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 13:44:04 +0100 Subject: [PATCH 42/99] Feature: [export] filter accompanying period which has no action - work --- .../AccompanyingCourseFilters/HasNoActionFilter.php | 12 ++++-------- .../ChillPersonBundle/translations/messages.fr.yml | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php index 771b8d063..54c28d027 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -12,10 +12,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class HasNoActionFilter implements FilterInterface { @@ -24,13 +24,9 @@ class HasNoActionFilter implements FilterInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { - if (!in_array('acpw', $qb->getAllAliases(), true)) { - $qb->join('acp.works', 'acpw'); - } - - $qb->andWhere('COUNT(acp.works) IS NULL'); + $qb->andWhere('NOT EXISTS (SELECT 1 FROM ' . AccompanyingPeriodWork::class . ' work WHERE work.accompanyingPeriod = acp)'); } public function applyOn(): string @@ -38,7 +34,7 @@ class HasNoActionFilter implements FilterInterface return Declarations::ACP_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { // no form } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 3821253ed..4b1919f8d 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -569,7 +569,7 @@ Filter by which has no referrer: Filtrer les parcours sans référent "Filtered acp which has no referrer on date: %date%": "Filtré les parcours sans référent à cette date: %date%" Has no referrer on this date: N'a pas de référent à cette date Filter by which has no action: Filtrer les parcours qui n’ont pas d’actions -Filtered acp which has no actions: Filtré les parcours qui n'ont pas d'actions +Filtered acp which has no actions: 'Filtré: uniquement les parcours qui n''ont pas d''actions' Group by number of actions: Grouper les parcours par nombre d’actions Filter by creator: Filtrer les parcours par créateur Filter by creator job: Filtrer les parcours par métier du créateur From c872ca7204805cd0462790f71eb9944b09a1add4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:05:16 +0100 Subject: [PATCH 43/99] Feature: [export] group accompanying period by number of actions --- .../ByActionNumberAggregator.php | 15 +++++++++++---- .../translations/messages.fr.yml | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php index 0f51b6feb..2dffccbbb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -23,9 +24,9 @@ class ByActionNumberAggregator implements AggregatorInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { - $qb->addSelect('AS acp_by_action_number_aggregator') + $qb->addSelect('(SELECT COUNT(acp_by_action_action.id) FROM ' . AccompanyingPeriodWork::class . ' acp_by_action_action WHERE acp_by_action_action.accompanyingPeriod = acp) AS acp_by_action_number_aggregator') ->addGroupBy('acp_by_action_number_aggregator'); } @@ -34,17 +35,23 @@ class ByActionNumberAggregator implements AggregatorInterface return Declarations::ACP_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { // No form needed } public function getLabels($key, array $values, $data) { - return static function ($value): string { + return static function ($value) { if ('_header' === $value) { + return 'export.aggregator.course.by_number_of_action.Number of actions'; + } + + if (null === $value) { return ''; } + + return $value; }; } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 4b1919f8d..8d5e055cd 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1013,6 +1013,8 @@ export: Household composition: Composition du ménage Group course by household composition: Grouper les parcours par composition familiale des ménages des usagers concernés Calc date: Date de calcul de la composition du ménage + by_number_of_action: + Number of actions: Nombre d'actions filter: course: by_user_scope: From 60f93f7f12ae2522c6a567b7aaa2e7d2c27f988a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:06:10 +0100 Subject: [PATCH 44/99] DX: more code style fixes --- .../Controller/ActivityControllerTest.php | 8 ++- .../Tests/Form/ActivityTypeTest.php | 4 +- .../Config/ConfigRepository.php | 16 ++++-- .../Service/Summary/SummaryBudget.php | 4 +- .../ParticipationControllerTest.php | 12 +++-- .../Export/Helper/ExportAddressHelper.php | 4 +- .../EntityToJsonTransformer.php | 4 +- .../Form/Type/ScopePickerType.php | 4 +- .../Tests/Entity/NotificationTest.php | 4 +- .../Tests/Form/Type/ScopePickerTypeTest.php | 4 +- .../Authorization/AuthorizationHelperTest.php | 4 +- .../Resolver/DefaultScopeResolverTest.php | 4 +- .../Resolver/ScopeResolverDispatcherTest.php | 4 +- .../NotificationOnTransition.php | 4 +- ...cialIssueConsistencyEntityListenerTest.php | 2 +- .../AccompanyingCourseApiControllerTest.php | 4 +- .../Controller/PersonControllerUpdateTest.php | 52 ++++++++++++++----- ...onControllerUpdateWithHiddenFieldsTest.php | 24 ++++++--- .../Tests/Household/MembersEditorTest.php | 8 ++- .../RelationshipDocGenNormalizerTest.php | 4 +- .../Tests/Timeline/TimelineProviderTest.php | 4 +- 21 files changed, 131 insertions(+), 47 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php index 55a1442f1..8a30a6c9b 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php @@ -369,8 +369,12 @@ final class ActivityControllerTest extends WebTestCase $center ); $reachableScopesId = array_intersect( - array_map(static function ($s) { return $s->getId(); }, $reachableScopesDelete), - array_map(static function ($s) { return $s->getId(); }, $reachableScopesUpdate) + array_map(static function ($s) { + return $s->getId(); + }, $reachableScopesDelete), + array_map(static function ($s) { + return $s->getId(); + }, $reachableScopesUpdate) ); if (count($reachableScopesId) === 0) { diff --git a/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php b/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php index d0b4b5bb2..b6cb6fc7b 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php @@ -188,7 +188,9 @@ final class ActivityTypeTest extends KernelTestCase // map all the values in an array $values = array_map( - static function ($choice) { return $choice->value; }, + static function ($choice) { + return $choice->value; + }, $view['activity']['durationTime']->vars['choices'] ); diff --git a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php index 2497bcf21..f28a83a4d 100644 --- a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php +++ b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php @@ -31,7 +31,9 @@ class ConfigRepository public function getChargesKeys(bool $onlyActive = false): array { - return array_map(static function ($element) { return $element['key']; }, $this->getCharges($onlyActive)); + return array_map(static function ($element) { + return $element['key']; + }, $this->getCharges($onlyActive)); } /** @@ -50,7 +52,9 @@ class ConfigRepository public function getResourcesKeys(bool $onlyActive = false): array { - return array_map(static function ($element) { return $element['key']; }, $this->getResources($onlyActive)); + return array_map(static function ($element) { + return $element['key']; + }, $this->getResources($onlyActive)); } /** @@ -70,14 +74,18 @@ class ConfigRepository private function getCharges(bool $onlyActive = false): array { return $onlyActive ? - array_filter($this->charges, static function ($el) { return $el['active']; }) + array_filter($this->charges, static function ($el) { + return $el['active']; + }) : $this->charges; } private function getResources(bool $onlyActive = false): array { return $onlyActive ? - array_filter($this->resources, static function ($el) { return $el['active']; }) + array_filter($this->resources, static function ($el) { + return $el['active']; + }) : $this->resources; } diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php index 6ae7e049b..f02d2e64a 100644 --- a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php +++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php @@ -61,7 +61,9 @@ class SummaryBudget implements SummaryBudgetInterface ]; } - $personIds = $household->getCurrentPersons()->map(static function (Person $p) { return $p->getId(); }); + $personIds = $household->getCurrentPersons()->map(static function (Person $p) { + return $p->getId(); + }); $ids = implode(', ', array_fill(0, count($personIds), '?')); $parameters = [...$personIds, $household->getId()]; diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php index dfb782a7d..fa1ecabbe 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php @@ -239,7 +239,9 @@ final class ParticipationControllerTest extends WebTestCase $this->personsIdsCache = array_merge( $this->personsIdsCache, $event->getParticipations()->map( - static function ($p) { return $p->getPerson()->getId(); } + static function ($p) { + return $p->getPerson()->getId(); + } ) ->toArray() ); @@ -303,7 +305,9 @@ final class ParticipationControllerTest extends WebTestCase $event = $this->getRandomEventWithMultipleParticipations(); $persons_id = implode(',', $event->getParticipations()->map( - static function ($p) { return $p->getPerson()->getId(); } + static function ($p) { + return $p->getPerson()->getId(); + } )->toArray()); $crawler = $this->client->request( @@ -329,7 +333,9 @@ final class ParticipationControllerTest extends WebTestCase $nbParticipations = $event->getParticipations()->count(); // get the persons_id participating on this event $persons_id = $event->getParticipations()->map( - static function ($p) { return $p->getPerson()->getId(); } + static function ($p) { + return $p->getPerson()->getId(); + } )->toArray(); // exclude the existing persons_ids from the new person $this->personsIdsCache = array_merge($this->personsIdsCache, $persons_id); diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 2f9a270ff..7d4245aa6 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -177,7 +177,9 @@ class ExportAddressHelper $prefixes = array_merge( $prefixes, array_map( - static function ($item) use ($prefix) { return $prefix . $item; }, + static function ($item) use ($prefix) { + return $prefix . $item; + }, self::COLUMN_MAPPING[$key] ) ); diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/EntityToJsonTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/EntityToJsonTransformer.php index ecd668d2b..46fa8799f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/EntityToJsonTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/EntityToJsonTransformer.php @@ -51,7 +51,9 @@ class EntityToJsonTransformer implements DataTransformerInterface } return array_map( - function ($item) { return $this->denormalizeOne($item); }, + function ($item) { + return $this->denormalizeOne($item); + }, $denormalized ); } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php index 1cba1ba58..f65677dc7 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php @@ -66,7 +66,9 @@ class ScopePickerType extends AbstractType $options['role'] instanceof Role ? $options['role']->getRole() : $options['role'], $options['center'] ), - static function (Scope $s) { return $s->isActive(); } + static function (Scope $s) { + return $s->isActive(); + } ); if (0 === count($items)) { diff --git a/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php b/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php index f5e203f78..9246cf1e6 100644 --- a/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Entity/NotificationTest.php @@ -134,7 +134,9 @@ final class NotificationTest extends KernelTestCase $this->assertEquals($senderId, $notification->getSender()->getId()); $this->assertCount(count($addressesIds), $notification->getUnreadBy()); - $unreadIds = $notification->getUnreadBy()->map(static function (User $u) { return $u->getId(); }); + $unreadIds = $notification->getUnreadBy()->map(static function (User $u) { + return $u->getId(); + }); foreach ($addressesIds as $addresseeId) { $this->assertContains($addresseeId, $unreadIds); diff --git a/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php index d64f68951..ce41c9a21 100644 --- a/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php @@ -96,7 +96,9 @@ final class ScopePickerTypeTest extends TypeTestCase $translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class); $translatableStringHelper->localize(Argument::type('array'))->will( - static function ($args) { return $args[0]['fr']; } + static function ($args) { + return $args[0]['fr']; + } ); $type = new ScopePickerType( diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php index 02d319042..cc5a49096 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php @@ -211,7 +211,9 @@ final class AuthorizationHelperTest extends KernelTestCase $centerA ); - $usernames = array_map(static function (User $u) { return $u->getUsername(); }, $users); + $usernames = array_map(static function (User $u) { + return $u->getUsername(); + }, $users); $this->assertContains('center a_social', $usernames); } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php index 7e6710a20..30d50fca5 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php @@ -33,7 +33,7 @@ final class DefaultScopeResolverTest extends TestCase public function testHasScopeInterface() { $scope = new Scope(); - $entity = new class($scope) implements HasScopeInterface { + $entity = new class ($scope) implements HasScopeInterface { public function __construct(Scope $scope) { $this->scope = $scope; @@ -52,7 +52,7 @@ final class DefaultScopeResolverTest extends TestCase public function testHasScopesInterface() { - $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { + $entity = new class ($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { public function __construct(Scope $scopeA, Scope $scopeB) { $this->scopes = [$scopeA, $scopeB]; diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php index e2c5d3879..31e5229bb 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php @@ -34,7 +34,7 @@ final class ScopeResolverDispatcherTest extends TestCase public function testHasScopeInterface() { $scope = new Scope(); - $entity = new class($scope) implements HasScopeInterface { + $entity = new class ($scope) implements HasScopeInterface { public function __construct(Scope $scope) { $this->scope = $scope; @@ -52,7 +52,7 @@ final class ScopeResolverDispatcherTest extends TestCase public function testHasScopesInterface() { - $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { + $entity = new class ($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { public function __construct(Scope $scopeA, Scope $scopeB) { $this->scopes = [$scopeA, $scopeB]; diff --git a/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/NotificationOnTransition.php b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/NotificationOnTransition.php index 608ae6fa1..7d2cadc37 100644 --- a/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/NotificationOnTransition.php +++ b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/NotificationOnTransition.php @@ -107,7 +107,9 @@ class NotificationOnTransition implements EventSubscriberInterface 'dest' => $subscriber, 'place' => $place, 'workflow' => $workflow, - 'is_dest' => in_array($subscriber->getId(), array_map(static function (User $u) { return $u->getId(); }, $entityWorkflow->futureDestUsers), true), + 'is_dest' => in_array($subscriber->getId(), array_map(static function (User $u) { + return $u->getId(); + }, $entityWorkflow->futureDestUsers), true), ]; $notification = new Notification(); diff --git a/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php index 0c8c3e0c3..8ac092647 100644 --- a/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php @@ -114,7 +114,7 @@ final class AccompanyingPeriodSocialIssueConsistencyEntityListenerTest extends T protected function generateClass(AccompanyingPeriod $period, Collection $socialIssues): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { - return new class($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { + return new class ($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { public Collection $socialIssues; public AccompanyingPeriod $period; diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php index 30c8e2a4c..154dbd884 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php @@ -342,7 +342,9 @@ final class AccompanyingCourseApiControllerTest extends WebTestCase // check that the person id is contained $participationsPersonsIds = array_map( - static function ($participation) { return $participation->person->id; }, + static function ($participation) { + return $participation->person->id; + }, $data->participations ); diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php index 8b2f4c141..bb70866e2 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php @@ -294,23 +294,49 @@ final class PersonControllerUpdateTest extends WebTestCase public function validTextFieldsProvider() { return [ - ['firstName', 'random Value', static function (Person $person) { return $person->getFirstName(); }], - ['lastName', 'random Value', static function (Person $person) { return $person->getLastName(); }], + ['firstName', 'random Value', static function (Person $person) { + return $person->getFirstName(); + }], + ['lastName', 'random Value', static function (Person $person) { + return $person->getLastName(); + }], // reminder: this value is capitalized - ['placeOfBirth', 'A PLACE', static function (Person $person) { return $person->getPlaceOfBirth(); }], - ['birthdate', '1980-12-15', static function (Person $person) { return $person->getBirthdate()->format('Y-m-d'); }], + ['placeOfBirth', 'A PLACE', static function (Person $person) { + return $person->getPlaceOfBirth(); + }], + ['birthdate', '1980-12-15', static function (Person $person) { + return $person->getBirthdate()->format('Y-m-d'); + }], // TODO test on phonenumber update // ['phonenumber', '+32123456789', static function (Person $person) { return $person->getPhonenumber(); }], - ['memo', 'jfkdlmq jkfldmsq jkmfdsq', static function (Person $person) { return $person->getMemo(); }], - ['countryOfBirth', 'BE', static function (Person $person) { return $person->getCountryOfBirth()->getCountryCode(); }], - ['nationality', 'FR', static function (Person $person) { return $person->getNationality()->getCountryCode(); }], - ['placeOfBirth', '', static function (Person $person) { return $person->getPlaceOfBirth(); }], - ['birthdate', '', static function (Person $person) { return $person->getBirthdate(); }], + ['memo', 'jfkdlmq jkfldmsq jkmfdsq', static function (Person $person) { + return $person->getMemo(); + }], + ['countryOfBirth', 'BE', static function (Person $person) { + return $person->getCountryOfBirth()->getCountryCode(); + }], + ['nationality', 'FR', static function (Person $person) { + return $person->getNationality()->getCountryCode(); + }], + ['placeOfBirth', '', static function (Person $person) { + return $person->getPlaceOfBirth(); + }], + ['birthdate', '', static function (Person $person) { + return $person->getBirthdate(); + }], //['phonenumber', '', static function (Person $person) { return $person->getPhonenumber(); }], - ['memo', '', static function (Person $person) { return $person->getMemo(); }], - ['countryOfBirth', null, static function (Person $person) { return $person->getCountryOfBirth(); }], - ['nationality', null, static function (Person $person) { return $person->getNationality(); }], - ['gender', Person::FEMALE_GENDER, static function (Person $person) { return $person->getGender(); }], + ['memo', '', static function (Person $person) { + return $person->getMemo(); + }], + ['countryOfBirth', null, static function (Person $person) { + return $person->getCountryOfBirth(); + }], + ['nationality', null, static function (Person $person) { + return $person->getNationality(); + }], + ['gender', Person::FEMALE_GENDER, static function (Person $person) { + return $person->getGender(); + }], ]; } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php index 7423b5388..403f89dd4 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php @@ -197,12 +197,24 @@ final class PersonControllerUpdateWithHiddenFieldsTest extends WebTestCase public function validTextFieldsProvider() { return [ - ['firstName', 'random Value', static function (Person $person) { return $person->getFirstName(); }], - ['lastName', 'random Value', static function (Person $person) { return $person->getLastName(); }], - ['birthdate', '15-12-1980', static function (Person $person) { return $person->getBirthdate()->format('d-m-Y'); }], - ['memo', 'jfkdlmq jkfldmsq jkmfdsq', static function (Person $person) { return $person->getMemo(); }], - ['birthdate', '', static function (Person $person) { return $person->getBirthdate(); }], - ['gender', Person::FEMALE_GENDER, static function (Person $person) { return $person->getGender(); }], + ['firstName', 'random Value', static function (Person $person) { + return $person->getFirstName(); + }], + ['lastName', 'random Value', static function (Person $person) { + return $person->getLastName(); + }], + ['birthdate', '15-12-1980', static function (Person $person) { + return $person->getBirthdate()->format('d-m-Y'); + }], + ['memo', 'jfkdlmq jkfldmsq jkmfdsq', static function (Person $person) { + return $person->getMemo(); + }], + ['birthdate', '', static function (Person $person) { + return $person->getBirthdate(); + }], + ['gender', Person::FEMALE_GENDER, static function (Person $person) { + return $person->getGender(); + }], ]; } diff --git a/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php index 9c0e884a5..a58560bdd 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php @@ -111,7 +111,9 @@ final class MembersEditorTest extends TestCase $this->assertCount(1, $notSharing); $this->assertCount(1, $sharings); - $getPerson = static function (HouseholdMember $m) { return $m->getPerson(); }; + $getPerson = static function (HouseholdMember $m) { + return $m->getPerson(); + }; $this->assertContains($person, $notSharing->map($getPerson)); } @@ -151,7 +153,9 @@ final class MembersEditorTest extends TestCase $this->assertCount(1, $notSharing); $this->assertCount(0, $sharings); - $getPerson = static function (HouseholdMember $m) { return $m->getPerson(); }; + $getPerson = static function (HouseholdMember $m) { + return $m->getPerson(); + }; $this->assertContains($person, $notSharing->map($getPerson)); } diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/RelationshipDocGenNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/RelationshipDocGenNormalizerTest.php index a6bab133a..05d2eace1 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/RelationshipDocGenNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/RelationshipDocGenNormalizerTest.php @@ -118,7 +118,9 @@ final class RelationshipDocGenNormalizerTest extends TestCase { $translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class); $translatableStringHelper->localize(Argument::type('array'))->will( - static function ($args) { return $args[0][array_keys($args[0])[0]]; } + static function ($args) { + return $args[0][array_keys($args[0])[0]]; + } ); $normalizer = new RelationshipDocGenNormalizer( diff --git a/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php b/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php index e76688357..6091c51a8 100644 --- a/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php @@ -67,7 +67,9 @@ final class TimelineProviderTest extends WebTestCase self::$em ->getRepository(\Chill\MainBundle\Entity\Scope::class) ->findAll(), - static function (Scope $scope) { return $scope->getName()['en'] === 'social'; } + static function (Scope $scope) { + return $scope->getName()['en'] === 'social'; + } ); $report = (new Report()) From 9cf06c147fdbc7138bd173f0d58cfd19b4231925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:25:52 +0100 Subject: [PATCH 45/99] Feature: [export][activity] Add an aggregator to group by sent / received --- .../Aggregator/SentReceivedAggregator.php | 28 +++++++++++++------ .../translations/messages.fr.yml | 10 +++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index 24000096f..3396faa80 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -16,15 +16,27 @@ use Chill\MainBundle\Export\AggregatorInterface; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class SentReceivedAggregator implements AggregatorInterface { + private TranslatorInterface $translator; + + /** + * @param TranslatorInterface $translator + */ + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function addRole(): ?string { return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { $qb->addSelect('activity.sentReceived AS activity_sentreceived_aggregator') ->addGroupBy('activity_sentreceived_aggregator'); @@ -35,16 +47,16 @@ class SentReceivedAggregator implements AggregatorInterface return Declarations::ACTIVITY; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { // No form needed } - public function getLabels($key, array $values, $data) + public function getLabels($key, array $values, $data): callable { - return static function ($value): string { + return function (?string $value): string { if ('_header' === $value) { - return ''; + return 'export.aggregator.activity.by_sent_received.Sent or received'; } switch ($value) { @@ -52,10 +64,10 @@ class SentReceivedAggregator implements AggregatorInterface return ''; case 'sent': - return 'is sent'; + return $this->translator->trans('export.aggregator.activity.by_sent_received.is sent'); case 'received': - return 'is received'; + return $this->translator->trans('export.aggregator.activity.by_sent_received.is received'); default: throw new LogicException(sprintf('The value %s is not valid', $value)); @@ -70,6 +82,6 @@ class SentReceivedAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group activity by sentreceived'; + return 'export.aggregator.activity.by_sent_received.Group activity by sentreceived'; } } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 1d5e7f1f2..c3d56185a 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -260,8 +260,6 @@ activity is not emergency: l'activité n'est pas urgente Filter activity by sentreceived: Filtrer les activités par envoyé/reçu 'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%" Accepted sentreceived: '' -is sent: envoyé -is received: reçu Filter activity by linked socialaction: Filtrer les activités par action liée 'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%" Filter activity by linked socialissue: Filtrer les activités par problématique liée @@ -280,7 +278,6 @@ Accepted userscope: Services Filter acp which has no activity: Filtrer les parcours qui n’ont pas d’activité 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é -Group activity by sentreceived: Grouper les activités par envoyé / reçu #aggregators Activity type: Type d'activité @@ -337,3 +334,10 @@ export: by_usersscope: Filter by users scope: Filtrer les activités par services d'au moins un utilisateur participant 'Filtered activity by users scope: only %scopes%': 'Filtré par service d''au moins un utilisateur participant: seulement %scopes%' + aggregator: + activity: + by_sent_received: + Sent or received: Envoyé ou reçu + is sent: envoyé + is received: reçu + Group activity by sentreceived: Grouper les activités par envoyé / reçu From 1bf7f9945cac5bbbcbe3f5b73fabe02ff0ea36dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:39:36 +0100 Subject: [PATCH 46/99] Feature: [export][action] Filter 'active' action: which does not have an end date --- .../Export/Filter/SocialWorkFilters/CurrentActionFilter.php | 6 +++--- .../config/services/exports_social_actions.yaml | 6 +++++- src/Bundle/ChillPersonBundle/translations/messages.fr.yml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php index cbf958182..cbdb64d8d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -23,9 +23,9 @@ class CurrentActionFilter implements FilterInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { - $qb->andWhere('acpw.startDate IS NULL'); + $qb->andWhere('acpw.endDate IS NULL'); } public function applyOn(): string @@ -33,7 +33,7 @@ class CurrentActionFilter implements FilterInterface return Declarations::SOCIAL_WORK_ACTION_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { //no form } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index 28401c3b3..8b2d9d2b8 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -38,6 +38,10 @@ services: - { name: chill.export_filter, alias: social_work_actions_treatingagent_filter } Chill\PersonBundle\Export\Filter\SocialWorkFilters\CurrentActionFilter: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_filter, alias: social_work_actions_current_filter } ## AGGREGATORS chill.person.export.aggregator_action_type: @@ -89,4 +93,4 @@ services: tags: - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } - Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: \ No newline at end of file + Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 8d5e055cd..df4b0fab2 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -576,7 +576,7 @@ Filter by creator job: Filtrer les parcours par métier du créateur Group by creator job: Grouper les parcours par métier du créateur Filter by current actions: Filtrer les actions en cours -Filtered by current action: Filtré les actions en cours +Filtered by current action: 'Filtré: uniquement les actions en cours (sans date de fin)' Group by current actions: Grouper les actions en cours Current action: Actions en cours Not current action: Actions terminées From cda25d3459d05d5f7dccead62a22f9c26416e5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:40:17 +0100 Subject: [PATCH 47/99] DX: more cs --- .../Export/Aggregator/SentReceivedAggregator.php | 4 ---- .../Tests/Security/Resolver/DefaultScopeResolverTest.php | 4 ++-- .../Tests/Security/Resolver/ScopeResolverDispatcherTest.php | 4 ++-- ...mpanyingPeriodSocialIssueConsistencyEntityListenerTest.php | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index 3396faa80..7d77a7c69 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -22,15 +22,11 @@ class SentReceivedAggregator implements AggregatorInterface { private TranslatorInterface $translator; - /** - * @param TranslatorInterface $translator - */ public function __construct(TranslatorInterface $translator) { $this->translator = $translator; } - public function addRole(): ?string { return null; diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php index 30d50fca5..7e6710a20 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php @@ -33,7 +33,7 @@ final class DefaultScopeResolverTest extends TestCase public function testHasScopeInterface() { $scope = new Scope(); - $entity = new class ($scope) implements HasScopeInterface { + $entity = new class($scope) implements HasScopeInterface { public function __construct(Scope $scope) { $this->scope = $scope; @@ -52,7 +52,7 @@ final class DefaultScopeResolverTest extends TestCase public function testHasScopesInterface() { - $entity = new class ($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { + $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { public function __construct(Scope $scopeA, Scope $scopeB) { $this->scopes = [$scopeA, $scopeB]; diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php index 31e5229bb..e2c5d3879 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php @@ -34,7 +34,7 @@ final class ScopeResolverDispatcherTest extends TestCase public function testHasScopeInterface() { $scope = new Scope(); - $entity = new class ($scope) implements HasScopeInterface { + $entity = new class($scope) implements HasScopeInterface { public function __construct(Scope $scope) { $this->scope = $scope; @@ -52,7 +52,7 @@ final class ScopeResolverDispatcherTest extends TestCase public function testHasScopesInterface() { - $entity = new class ($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { + $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { public function __construct(Scope $scopeA, Scope $scopeB) { $this->scopes = [$scopeA, $scopeB]; diff --git a/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php index 8ac092647..0c8c3e0c3 100644 --- a/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php @@ -114,7 +114,7 @@ final class AccompanyingPeriodSocialIssueConsistencyEntityListenerTest extends T protected function generateClass(AccompanyingPeriod $period, Collection $socialIssues): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { - return new class ($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { + return new class($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { public Collection $socialIssues; public AccompanyingPeriod $period; From e07d2ab467933f15194b5aa7b3c9e7c6e8716cd5 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 14:41:25 +0100 Subject: [PATCH 48/99] voter aside activity created --- .../ChillAsideActivityExtension.php | 1 + .../src/Security/AsideActivityVoter.php | 79 +++++++++++++++++++ .../src/config/services/security.yaml | 7 ++ 3 files changed, 87 insertions(+) create mode 100644 src/Bundle/ChillAsideActivityBundle/src/Security/AsideActivityVoter.php create mode 100644 src/Bundle/ChillAsideActivityBundle/src/config/services/security.yaml diff --git a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php index ef6c5d69b..927de1845 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php @@ -30,6 +30,7 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte $loader->load('services.yaml'); $loader->load('services/form.yaml'); $loader->load('services/menu.yaml'); + $loader->load('services/security.yaml'); $loader->load('services/export.yaml'); } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Security/AsideActivityVoter.php b/src/Bundle/ChillAsideActivityBundle/src/Security/AsideActivityVoter.php new file mode 100644 index 000000000..6b308b5f2 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/Security/AsideActivityVoter.php @@ -0,0 +1,79 @@ +voterHelper = $voterHelperFactory + ->generate(self::class) + ->addCheckFor(Center::class, [self::STATS]) + ->build(); + } + + /** + * @return string[] + */ + public function getRoles(): array + { + return $this->getAttributes(); + } + + /** + * @return string[][] + */ + public function getRolesWithHierarchy(): array + { + return ['Aside activity' => $this->getRoles()]; + } + + /** + * @return string[] + */ + public function getRolesWithoutScope(): array + { + return $this->getAttributes(); + } + + protected function supports($attribute, $subject) + { + return $this->voterHelper->supports($attribute, $subject); + } + + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool + { + if (!$token->getUser() instanceof User) { + return false; + } + + return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); + } + + private function getAttributes(): array + { + return [self::STATS]; + } +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/config/services/security.yaml b/src/Bundle/ChillAsideActivityBundle/src/config/services/security.yaml new file mode 100644 index 000000000..eb3327959 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/config/services/security.yaml @@ -0,0 +1,7 @@ +services: + Chill\AsideActivityBundle\Security\AsideActivityVoter: + autowire: true + autoconfigure: true + tags: + - { name: security.voter } + - { name: chill.role } \ No newline at end of file From 9c3533d1060f02385ac2c89aa6db9324a4f55f1b Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 14:42:44 +0100 Subject: [PATCH 49/99] count aside activity --- .../src/Export/Export/CountAsideActivity.php | 8 +++----- .../src/translations/messages.fr.yml | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index d1d69f0c8..304e0a283 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -13,6 +13,7 @@ namespace Chill\AsideActivityBundle\Export\Export; use Chill\AsideActivityBundle\Export\Declarations; use Chill\AsideActivityBundle\Repository\AsideActivityRepository; +use Chill\AsideActivityBundle\Security\AsideActivityVoter; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; @@ -32,7 +33,6 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { - // TODO: Implement buildForm() method. } public function getAllowedFormattersTypes(): array @@ -88,16 +88,14 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface { $qb = $this->repository->createQueryBuilder('aside'); - $qb->andWhere(); - - $qb->select('COUNT() AS export_result'); + $qb->select('COUNT(DISTINCT aside.id) AS export_result'); return $qb; } public function requiredRole(): string { - return ''; + return AsideActivityVoter::STATS; } public function supportsModifiers(): array diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml index 5b298ed68..ed54fd488 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml @@ -168,6 +168,7 @@ Aside activity type configuration: Configuration des categories d'activités ann Aside activity configuration: Configuration des activités annexes # exports +Exports of aside activities: Exports des activités annexes Count aside activities: Nombre d'activités annexes Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères Filter by aside activity date: Filtrer les activités annexes par date From 63d38e35f729d1646b93ed141a2bff7d257872e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 14:55:12 +0100 Subject: [PATCH 50/99] Feature: [export][work] Group by current action --- .../CurrentActionAggregator.php | 24 ++++++++++++------- .../services/exports_social_actions.yaml | 4 ++++ .../translations/messages.fr.yml | 9 ++++--- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index a77838167..58fcb2874 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -16,19 +16,27 @@ use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CurrentActionAggregator implements AggregatorInterface { + private TranslatorInterface $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + public function addRole(): ?string { return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { $qb ->addSelect(' - (CASE true WHEN acpw.startDate IS NULL ELSE false END) + (CASE WHEN acpw.endDate IS NULL THEN true ELSE false END) AS acpw_current_action_aggregator ') ->addGroupBy('acpw_current_action_aggregator'); @@ -39,24 +47,24 @@ class CurrentActionAggregator implements AggregatorInterface return Declarations::SOCIAL_WORK_ACTION_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { // No form needed } public function getLabels($key, array $values, $data) { - return static function ($value): string { + return function ($value): string { if ('_header' === $value) { - return ''; + return 'export.aggregator.course_work.by_current_action.Current action ?'; } switch ($value) { case true: - return 'Current action'; + return $this->translator->trans('export.aggregator.course_work.by_current_action.Current action'); case false: - return 'Not current action'; + return $this->translator->trans('export.aggregator.course_work.by_current_action.Not current action'); default: throw new LogicException(sprintf('The value %s is not valid', $value)); @@ -71,6 +79,6 @@ class CurrentActionAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group by current actions'; + return 'export.aggregator.course_work.by_current_action.Group by current actions'; } } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml index 8b2d9d2b8..13c51762f 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_social_actions.yaml @@ -94,3 +94,7 @@ services: - { name: chill.export_aggregator, alias: social_work_actions_goal_result_aggregator } Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators\CurrentActionAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: social_work_actions_current_aggregator } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index df4b0fab2..0833f57e3 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -577,9 +577,6 @@ Group by creator job: Grouper les parcours par métier du créateur Filter by current actions: Filtrer les actions en cours Filtered by current action: 'Filtré: uniquement les actions en cours (sans date de fin)' -Group by current actions: Grouper les actions en cours -Current action: Actions en cours -Not current action: Actions terminées Filter by start date evaluations: Filtrer les évaluations par date de début Filter by end date evaluations: Filtrer les évaluations par date de fin start period date: Date de début de la période @@ -1015,6 +1012,12 @@ export: Calc date: Date de calcul de la composition du ménage by_number_of_action: Number of actions: Nombre d'actions + course_work: + by_current_action: + Current action ?: Action en cours ? + Group by current actions: Grouper les actions en cours + Current action: Action en cours + Not current action: Action terminée filter: course: by_user_scope: From d8104c4443b948d0433ff438f88279c3ebe33c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 15:08:04 +0100 Subject: [PATCH 51/99] DX: prevent collision in parameter name in evaluation / by start date filter --- .../EvaluationFilters/ByStartDateFilter.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index e21a1ea68..f12b5e805 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -14,7 +14,7 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; -use DateTime; +use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -26,12 +26,12 @@ class ByStartDateFilter implements FilterInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { $qb - ->andWhere('workeval.startDate IS BETWEEN :start_date and :end_date') - ->setParameter('start_date', $data['start_date'], Types::DATE_IMMUTABLE) - ->setParameter('end_date', $data['end_date'], Types::DATE_IMMUTABLE); + ->andWhere('workeval.startDate BETWEEN :work_eval_by_start_date_start_date and :work_eval_by_start_date_end_date') + ->setParameter('work_eval_by_start_date_start_date', $data['start_date'], Types::DATE_IMMUTABLE) + ->setParameter('work_eval_by_start_date_end_date', $data['end_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -39,16 +39,18 @@ class ByStartDateFilter implements FilterInterface return Declarations::EVAL_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { $builder ->add('start_date', ChillDateType::class, [ 'label' => 'start period date', - 'data' => new DateTime(), + 'data' => new DateTimeImmutable('1 year ago'), + 'input' => 'datetime_immutable', ]) ->add('end_date', ChillDateType::class, [ 'label' => 'end period date', - 'data' => new DateTime(), + 'data' => new DateTimeImmutable(), + 'input' => 'datetime_immutable', ]); } From 2d40c38c88fed58648f713bbd47a2dac1ca22784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 15:56:48 +0100 Subject: [PATCH 52/99] Feature: [export][evaluation] add by end date filter --- .../EvaluationFilters/ByEndDateFilter.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index 5c509d50c..f828da109 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -14,7 +14,7 @@ namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Export\Declarations; -use DateTime; +use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -26,12 +26,12 @@ class ByEndDateFilter implements FilterInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { $qb - ->andWhere('workeval.endDate IS BETWEEN :start_date and :end_date') - ->setParameter('start_date', $data['start_date'], Types::DATE_IMMUTABLE) - ->setParameter('end_date', $data['end_date'], Types::DATE_IMMUTABLE); + ->andWhere('workeval.endDate BETWEEN :work_eval_by_end_date_start_date and :work_eval_by_end_date_end_date') + ->setParameter('work_eval_by_end_date_start_date', $data['start_date'], Types::DATE_IMMUTABLE) + ->setParameter('work_eval_by_end_date_end_date', $data['end_date'], Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -39,16 +39,18 @@ class ByEndDateFilter implements FilterInterface return Declarations::EVAL_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { $builder ->add('start_date', ChillDateType::class, [ 'label' => 'start period date', - 'data' => new DateTime(), + 'data' => new DateTimeImmutable('1 year ago'), + 'input' => 'datetime_immutable', ]) ->add('end_date', ChillDateType::class, [ 'label' => 'end period date', - 'data' => new DateTime(), + 'data' => new DateTimeImmutable(), + 'input' => 'datetime_immutable', ]); } From f0b2ec13486f971ec4e62b0fc3418380a547b85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 16:17:10 +0100 Subject: [PATCH 53/99] Feature: [export][evaluation] filter by current evaluation (without any end date) --- .../Filter/EvaluationFilters/CurrentEvaluationsFilter.php | 4 ++-- src/Bundle/ChillPersonBundle/translations/messages.fr.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php index 50c95600e..140f6c3cb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -23,7 +23,7 @@ class CurrentEvaluationsFilter implements FilterInterface return null; } - public function alterQuery(QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data): void { $qb->andWhere('workeval.endDate IS NULL'); } @@ -33,7 +33,7 @@ class CurrentEvaluationsFilter implements FilterInterface return Declarations::EVAL_TYPE; } - public function buildForm(FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder): void { //no form needed } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 0833f57e3..3764325af 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -584,7 +584,7 @@ end period date: Date de fin de la période "Filtered by start date: between %start_date% and %end_date%": "Filtré par la date de début: comprise entre %start_date% et %end_date%" "Filtered by end date: between %start_date% and %end_date%": "Filtré par la date de fin: comprise entre %start_date% et %end_date%" Filter by current evaluations: Filtrer les évaluations en cours -"Filtered by current evaluations": "Filtré selon les évaluations en cours" +"Filtered by current evaluations": "Filtré: uniquement les évaluations en cours" Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance From 4ca10ce38d11f991a0d80e7d264253fbe2374097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 16:26:56 +0100 Subject: [PATCH 54/99] Feature: [export][evaluation] Adding group by evaluation having end date --- .../HavingEndDateAggregator.php | 23 +++++++++++-------- .../config/services/exports_evaluation.yaml | 7 ++++++ .../translations/messages.fr.yml | 9 +++++--- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php index af801b74d..e33bb326f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php @@ -16,9 +16,17 @@ use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class HavingEndDateAggregator implements AggregatorInterface { + private TranslatorInterface $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + public function addRole(): ?string { return null; @@ -27,10 +35,7 @@ class HavingEndDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { $qb - ->addSelect(' - CASE true WHEN workeval.endDAte IS NULL ELSE false END - AS eval_enddate_aggregator - ') + ->addSelect('CASE WHEN workeval.endDate IS NULL THEN true ELSE false END AS eval_enddate_aggregator') ->addGroupBy('eval_enddate_aggregator'); } @@ -46,17 +51,17 @@ class HavingEndDateAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return static function ($value): string { + return function ($value): string { if ('_header' === $value) { - return ''; + return 'export.aggregator.eval.by_end_date.Has end date ?'; } switch ($value) { case true: - return 'enddate is specified'; + return $this->translator->trans('export.aggregator.eval.by_end_date.enddate is specified'); case false: - return 'enddate is not specified'; + return $this->translator->trans('export.aggregator.eval.by_end_date.enddate is not specified'); default: throw new LogicException(sprintf('The value %s is not valid', $value)); @@ -71,6 +76,6 @@ class HavingEndDateAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group evaluations having end date'; + return 'export.aggregator.eval.by_end_date.Group evaluations having end date'; } } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml index a389c1f80..f58b7112b 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_evaluation.yaml @@ -73,3 +73,10 @@ services: autoconfigure: true tags: - { name: chill.export_aggregator, alias: evaluation_bymaxdate_aggregator } + + Chill\PersonBundle\Export\Aggregator\EvaluationAggregators\HavingEndDateAggregator: + autowire: true + autoconfigure: true + tags: + - { name: chill.export_aggregator, alias: evaluation_byend_date_aggregator } + diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 3764325af..89808d900 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -626,9 +626,6 @@ maxdate is specified: la date d'échéance est spécifiée maxdate is not specified: la date d'échéance n'est pas spécifiée "Filtered by maxdate: only %choice%": "Filtré par date d'échéance: uniquement si %choice%" -Group evaluations having end date: Grouper les évaluations qui ont une date de fin -enddate is specified: la date de fin est spécifiée -enddate is not specified: la date de fin n'est pas spécifiée ## household filters/aggr Filter by composition: Filtrer les ménages par composition familiale @@ -1018,6 +1015,12 @@ export: Group by current actions: Grouper les actions en cours Current action: Action en cours Not current action: Action terminée + eval: + by_end_date: + Has end date ?: Évaluation en cours ? + Group evaluations having end date: Grouper les évaluations en cours (avec ou sans date de fin) + enddate is specified: la date de fin est spécifiée + enddate is not specified: la date de fin n'est pas spécifiée filter: course: by_user_scope: From 0255f12fa913c39ce5efbd4da9a63b23d5cf7061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 2 Nov 2022 16:42:23 +0100 Subject: [PATCH 55/99] Feature: [export][evaluation] Group evaluation by start date --- .../ByStartDateAggregator.php | 54 +++++++++++++++++-- .../translations/messages.fr.yml | 4 +- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index e64245d53..a41fe2451 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -14,10 +14,23 @@ namespace Chill\PersonBundle\Export\Aggregator\EvaluationAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ByStartDateAggregator implements AggregatorInterface { + private const CHOICES = [ + 'by month' => 'month', + 'by week' => 'week', + 'by year' => 'year', + ]; + + private const DEFAULT_CHOICE = 'year'; + + private TranslatorInterface $translator; + public function addRole(): ?string { return null; @@ -25,8 +38,29 @@ class ByStartDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS eval_by_start_date_aggregator') - ->addGroupBy('eval_by_start_date_aggregator'); + switch ($data['frequency']) { + case 'month': + $fmt = 'YYYY-MM'; + + break; + + case 'week': + $fmt = 'YYYY-IW'; + + break; + + case 'year': + $fmt = 'YYYY'; + + break; + + default: + throw new LogicException(sprintf("The frequency data '%s' is invalid.", $data['frequency'])); + } + + $qb->addSelect(sprintf("TO_CHAR(workeval.startDate, '%s') AS eval_by_start_date_aggregator", $fmt)); + $qb->addGroupBy(' eval_by_start_date_aggregator'); + $qb->addOrderBy(' eval_by_start_date_aggregator', 'ASC'); } public function applyOn(): string @@ -36,15 +70,27 @@ class ByStartDateAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - // No form needed + $builder->add('frequency', ChoiceType::class, [ + 'choices' => self::CHOICES, + 'multiple' => false, + 'expanded' => true, + 'empty_data' => self::DEFAULT_CHOICE, + 'data' => self::DEFAULT_CHOICE, + ]); } public function getLabels($key, array $values, $data) { return static function ($value): string { if ('_header' === $value) { + return 'export.aggregator.eval.by_start_date_period.Start date period'; + } + + if (null === $value) { return ''; } + + return $value; }; } @@ -55,6 +101,6 @@ class ByStartDateAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group by start date evaluations'; + return 'export.aggregator.eval.by_start_date_period.Group by start date evaluations'; } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 89808d900..9f6eda592 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -585,7 +585,6 @@ end period date: Date de fin de la période "Filtered by end date: between %start_date% and %end_date%": "Filtré par la date de fin: comprise entre %start_date% et %end_date%" Filter by current evaluations: Filtrer les évaluations en cours "Filtered by current evaluations": "Filtré: uniquement les évaluations en cours" -Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance @@ -1021,6 +1020,9 @@ export: Group evaluations having end date: Grouper les évaluations en cours (avec ou sans date de fin) enddate is specified: la date de fin est spécifiée enddate is not specified: la date de fin n'est pas spécifiée + by_start_date_period: + Start date period: Début (par periode) + Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début filter: course: by_user_scope: From 481be3299756e084951b20f382fefda3841e56aa Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 20:02:46 +0100 Subject: [PATCH 56/99] filters and aggregator aside activity --- .../Aggregator/ByActivityTypeAggregator.php | 32 ++++++- .../src/Export/Export/CountAsideActivity.php | 6 +- .../Export/Filter/ByActivityTypeFilter.php | 57 ++++++++++-- .../src/Export/Filter/ByDateFilter.php | 92 +++++++++++++++++-- .../AsideActivityCategoryRepository.php | 5 + .../src/config/services/export.yaml | 18 ++++ .../src/translations/messages.fr.yml | 22 +++-- 7 files changed, 202 insertions(+), 30 deletions(-) diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index 488885bde..6c91c9336 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -12,12 +12,24 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Aggregator; use Chill\AsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository; use Chill\MainBundle\Export\AggregatorInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class ByActivityTypeAggregator implements AggregatorInterface { + private AsideActivityCategoryRepository $asideActivityCategoryRepository; + + private TranslatableStringHelper $translatableStringHelper; + + public function __construct(AsideActivityCategoryRepository $asideActivityCategoryRepository, TranslatableStringHelper $translatableStringHelper) + { + $this->asideActivityCategoryRepository = $asideActivityCategoryRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + public function addRole(): ?string { return null; @@ -25,8 +37,8 @@ class ByActivityTypeAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS aside_by_activity_type_aggregator') - ->addGroupBy('aside_by_activity_type_aggregator'); + $qb->addSelect('IDENTITY(aside.type) AS by_aside_activity_type_aggregator') + ->addGroupBy('by_aside_activity_type_aggregator'); } public function applyOn(): string @@ -41,20 +53,30 @@ class ByActivityTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return static function ($value): string { + $this->asideActivityCategoryRepository->findBy(['id' => $values]); + + return function ($value): string { if ('_header' === $value) { + return 'export.aggregator.Aside activity type'; + } + + if (null === $value) { return ''; } + + $t = $this->asideActivityCategoryRepository->find($value); + + return $this->translatableStringHelper->localize($t->getTitle()); }; } public function getQueryKeys($data): array { - return ['aside_by_activity_type_aggregator']; + return ['by_aside_activity_type_aggregator']; } public function getTitle(): string { - return 'Group by aside activity type'; + return 'export.aggregator.Group by aside activity type'; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index 304e0a283..6abcd5ec8 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -42,12 +42,12 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface public function getDescription(): string { - return 'Count aside activities by various parameters.'; + return 'export.Count aside activities by various parameters.'; } public function getGroup(): string { - return 'Exports of aside activities'; + return 'export.Exports of aside activities'; } public function getLabels($key, array $values, $data) @@ -76,7 +76,7 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface public function getTitle(): string { - return 'Count aside activities'; + return 'export.Count aside activities'; } public function getType(): string diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 354bd9f3c..85b327795 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -11,13 +11,34 @@ declare(strict_types=1); namespace Chill\AsideActivityBundle\Export\Filter; +use Chill\AsideActivityBundle\Entity\AsideActivityCategory; use Chill\AsideActivityBundle\Export\Declarations; +use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository; +use Chill\AsideActivityBundle\Templating\Entity\CategoryRender; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\QueryBuilder; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; class ByActivityTypeFilter implements FilterInterface { + private AsideActivityCategoryRepository $asideActivityTypeRepository; + + private CategoryRender $categoryRender; + + private TranslatableStringHelperInterface $translatableStringHelper; + + public function __construct( + CategoryRender $categoryRender, + TranslatableStringHelperInterface $translatableStringHelper, + AsideActivityCategoryRepository $asideActivityTypeRepository + ) { + $this->categoryRender = $categoryRender; + $this->asideActivityTypeRepository = $asideActivityTypeRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + public function addRole(): ?string { return null; @@ -25,11 +46,10 @@ class ByActivityTypeFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + $clause = $qb->expr()->in('aside.type', ':types'); + + $qb->andWhere($clause); + $qb->setParameter('types', $data['types']); } public function applyOn(): string @@ -39,17 +59,38 @@ class ByActivityTypeFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - //$builder->add(); + $builder + ->add('types', EntityType::class, [ + 'class' => AsideActivityCategory::class, + 'choices' => $this->asideActivityTypeRepository->findAllActive(), + 'required' => false, + 'multiple' => true, + 'expanded' => false, + 'attr' => [ + 'class' => 'select2', + ], + 'choice_label' => function (AsideActivityCategory $category) { + $options = []; + + return $this->categoryRender->renderString($category, $options); + }, + ]); } public function describeAction($data, $format = 'string'): array { - return ['', [ + $types = array_map( + fn (AsideActivityCategory $t): string => $this->translatableStringHelper->localize($t->getName()), + $this->asideActivityTypeRepository->findBy(['id' => $data['types']->toArray()]) + ); + + return ['export.filter.Filtered by aside activity type: only %type%', [ + '%type%' => implode(', ', $types), ]]; } public function getTitle(): string { - return 'Filter by aside activity type'; + return 'export.filter.Filter by aside activity type'; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index 5a63e8e94..a7595281d 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -13,11 +13,26 @@ namespace Chill\AsideActivityBundle\Export\Filter; use Chill\AsideActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\Export\FilterType; +use DateTime; +use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; +use Symfony\Contracts\Translation\TranslatorInterface; class ByDateFilter implements FilterInterface { + protected TranslatorInterface $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + public function addRole(): ?string { return null; @@ -25,11 +40,22 @@ class ByDateFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb - ->andWhere( - $qb->expr()->in('', ':') - ) - ->setParameter('', $data[]); + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->between( + 'aside.date', + ':date_from', + ':date_to' + ); + + if ($where instanceof Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('date_from', $data['date_from']); + $qb->setParameter('date_to', $data['date_to']); } public function applyOn(): string @@ -39,17 +65,67 @@ class ByDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - //$builder->add(); + $builder + ->add('date_from', ChillDateType::class, [ + 'label' => 'export.filter.Aside activities after this date', + 'data' => new DateTime(), + ]) + ->add('date_to', ChillDateType::class, [ + 'label' => 'export.filter.Aside activities before this date', + 'data' => new DateTime(), + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + /** @var \Symfony\Component\Form\FormInterface $filterForm */ + $filterForm = $event->getForm()->getParent(); + $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); + + if (true === $enabled) { + // if the filter is enabled, add some validation + $form = $event->getForm(); + $date_from = $form->get('date_from')->getData(); + $date_to = $form->get('date_to')->getData(); + + // check that fields are not empty + if (null === $date_from) { + $form->get('date_from')->addError(new FormError( + $this->translator->trans('This field ' + . 'should not be empty') + )); + } + + if (null === $date_to) { + $form->get('date_to')->addError(new FormError( + $this->translator->trans('This field ' + . 'should not be empty') + )); + } + + // check that date_from is before date_to + if ( + (null !== $date_from && null !== $date_to) + && $date_from >= $date_to + ) { + $form->get('date_to')->addError(new FormError( + $this->translator->trans('export.filter.This date should be after ' + . 'the date given in "Implied in an aside activity after ' + . 'this date" field') + )); + } + } + }); } public function describeAction($data, $format = 'string'): array { - return ['', [ + return ['export.filter.Filtered by aside activities between %dateFrom% and %dateTo%', [ + '%dateFrom%' => $data['date_from']->format('d-m-Y'), + '%dateTo%' => $data['date_to']->format('d-m-Y'), ]]; } public function getTitle(): string { - return 'Filter by aside activity date'; + return 'export.filter.Filter by aside activity date'; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php index 85ea9faf4..918cec586 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php @@ -38,6 +38,11 @@ class AsideActivityCategoryRepository implements ObjectRepository return $this->repository->findAll(); } + public function findAllActive(): array + { + return $this->repository->findBy(['isActive' => true]); + } + /** * @param mixed|null $limit * @param mixed|null $offset diff --git a/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml b/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml index 579791d41..1b6b05e1c 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml +++ b/src/Bundle/ChillAsideActivityBundle/src/config/services/export.yaml @@ -7,3 +7,21 @@ services: Chill\AsideActivityBundle\Export\Export\CountAsideActivity: tags: - { name: chill.export, alias: 'count_aside_activity' } + + ## Filters + chill.aside_activity.export.date_filter: + class: Chill\AsideActivityBundle\Export\Filter\ByDateFilter + tags: + - { name: chill.export_filter, alias: 'aside_activity_date_filter' } + + chill.aside_activity.export.type_filter: + class: Chill\AsideActivityBundle\Export\Filter\ByActivityTypeFilter + tags: + - { name: chill.export_filter, alias: 'aside_activity_type_filter' } + + ## Aggregators + + chill.aside_activity.export.type_aggregator: + class: Chill\AsideActivityBundle\Export\Aggregator\ByActivityTypeAggregator + tags: + - { name: chill.export_aggregator, alias: activity_type_aggregator } \ No newline at end of file diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml index ed54fd488..35a4d6a22 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml @@ -168,9 +168,19 @@ Aside activity type configuration: Configuration des categories d'activités ann Aside activity configuration: Configuration des activités annexes # exports -Exports of aside activities: Exports des activités annexes -Count aside activities: Nombre d'activités annexes -Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères -Filter by aside activity date: Filtrer les activités annexes par date -Filter by aside activity type: Filtrer les activités annexes par type d'activité -Group by aside activity type: Grouper les activités annexes par type d'activité \ No newline at end of file +export: + Exports of aside activities: Exports des activités annexes + Count aside activities: Nombre d'activités annexes + Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères + filter: + Filter by aside activity date: Filtrer les activités annexes par date + Filter by aside activity type: Filtrer les activités annexes par type d'activité + 'Filtered by aside activity type: only %type%': "Filtré par type d'activité annexe: uniquement %type%" + This date should be after the date given in "Implied in an aside activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités annexes après cette date" + Aside activities after this date: Actvitités annexes après cette date + Aside activities before this date: Actvitités annexes avant cette date + aggregator: + Group by aside activity type: Grouper les activités annexes par type d'activité + Aside activity type: Type d'activité annexe + + From d3f03fb27cfc8f37fd1e6b7eb6cbf8108c65c2dc Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 2 Nov 2022 20:06:03 +0100 Subject: [PATCH 57/99] evaluations aggregators --- .../ByEndDateAggregator.php | 54 +++++++++++++++++-- .../ByMaxDateAggregator.php | 54 +++++++++++++++++-- .../ByStartDateAggregator.php | 10 ++-- .../translations/messages.fr.yml | 8 ++- 4 files changed, 111 insertions(+), 15 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php index 40b035a02..2f4275c49 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -14,10 +14,23 @@ namespace Chill\PersonBundle\Export\Aggregator\EvaluationAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ByEndDateAggregator implements AggregatorInterface { + private const CHOICES = [ + 'by week' => 'week', + 'by month' => 'month', + 'by year' => 'year', + ]; + + private const DEFAULT_CHOICE = 'year'; + + private TranslatorInterface $translator; + public function addRole(): ?string { return null; @@ -25,8 +38,29 @@ class ByEndDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS eval_by_end_date_aggregator') - ->addGroupBy('eval_by_end_date_aggregator'); + switch ($data['frequency']) { + case 'week': + $fmt = 'YYYY-IW'; + + break; + + case 'month': + $fmt = 'YYYY-MM'; + + break; + + case 'year': + $fmt = 'YYYY'; + + break; + + default: + throw new LogicException(sprintf("The frequency data '%s' is invalid.", $data['frequency'])); + } + + $qb->addSelect(sprintf("TO_CHAR(workeval.endDate, '%s') AS eval_by_end_date_aggregator", $fmt)); + $qb->addGroupBy(' eval_by_end_date_aggregator'); + $qb->addOrderBy(' eval_by_end_date_aggregator', 'ASC'); } public function applyOn(): string @@ -36,15 +70,27 @@ class ByEndDateAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - // No form needed + $builder->add('frequency', ChoiceType::class, [ + 'choices' => self::CHOICES, + 'multiple' => false, + 'expanded' => true, + 'empty_data' => self::DEFAULT_CHOICE, + 'data' => self::DEFAULT_CHOICE, + ]); } public function getLabels($key, array $values, $data) { return static function ($value): string { if ('_header' === $value) { + return 'export.aggregator.eval.by_end_date.End date period'; + } + + if (null === $value) { return ''; } + + return $value; }; } @@ -55,6 +101,6 @@ class ByEndDateAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group by end date evaluations'; + return 'export.aggregator.eval.by_end_date.Group by end date evaluations'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php index 36ab0f50b..9283fd9dc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -14,10 +14,23 @@ namespace Chill\PersonBundle\Export\Aggregator\EvaluationAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ByMaxDateAggregator implements AggregatorInterface { + private const CHOICES = [ + 'by week' => 'week', + 'by month' => 'month', + 'by year' => 'year', + ]; + + private const DEFAULT_CHOICE = 'year'; + + private TranslatorInterface $translator; + public function addRole(): ?string { return null; @@ -25,8 +38,29 @@ class ByMaxDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - $qb->addSelect('AS eval_by_max_date_aggregator') - ->addGroupBy('eval_by_max_date_aggregator'); + switch ($data['frequency']) { + case 'week': + $fmt = 'YYYY-IW'; + + break; + + case 'month': + $fmt = 'YYYY-MM'; + + break; + + case 'year': + $fmt = 'YYYY'; + + break; + + default: + throw new LogicException(sprintf("The frequency data '%s' is invalid.", $data['frequency'])); + } + + $qb->addSelect(sprintf("TO_CHAR(workeval.maxDate, '%s') AS eval_by_max_date_aggregator", $fmt)); + $qb->addGroupBy(' eval_by_max_date_aggregator'); + $qb->addOrderBy(' eval_by_max_date_aggregator', 'ASC'); } public function applyOn(): string @@ -36,15 +70,27 @@ class ByMaxDateAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - // No form needed + $builder->add('frequency', ChoiceType::class, [ + 'choices' => self::CHOICES, + 'multiple' => false, + 'expanded' => true, + 'empty_data' => self::DEFAULT_CHOICE, + 'data' => self::DEFAULT_CHOICE, + ]); } public function getLabels($key, array $values, $data) { return static function ($value): string { if ('_header' === $value) { + return 'export.aggregator.eval.by_max_date.Max date'; + } + + if (null === $value) { return ''; } + + return $value; }; } @@ -55,6 +101,6 @@ class ByMaxDateAggregator implements AggregatorInterface public function getTitle(): string { - return 'Group by max date evaluations'; + return 'export.aggregator.eval.by_max_date.Group by max date evaluations'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index a41fe2451..cd183b25e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -22,8 +22,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ByStartDateAggregator implements AggregatorInterface { private const CHOICES = [ - 'by month' => 'month', 'by week' => 'week', + 'by month' => 'month', 'by year' => 'year', ]; @@ -39,13 +39,13 @@ class ByStartDateAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { switch ($data['frequency']) { - case 'month': - $fmt = 'YYYY-MM'; + case 'week': + $fmt = 'YYYY-IW'; break; - case 'week': - $fmt = 'YYYY-IW'; + case 'month': + $fmt = 'YYYY-MM'; break; diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 7780c76dd..dca6c91f6 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -587,8 +587,6 @@ end period date: Date de fin de la période "Filtered by end date: between %start_date% and %end_date%": "Filtré par la date de fin: comprise entre %start_date% et %end_date%" Filter by current evaluations: Filtrer les évaluations en cours "Filtered by current evaluations": "Filtré: uniquement les évaluations en cours" -Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin -Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance ## social actions filters/aggr Filter by treating agent scope: Filtrer les actions par service de l'agent traitant @@ -1022,9 +1020,15 @@ export: Group evaluations having end date: Grouper les évaluations en cours (avec ou sans date de fin) enddate is specified: la date de fin est spécifiée enddate is not specified: la date de fin n'est pas spécifiée + Group by end date evaluations: Grouper les évaluations par semaine/mois/année de la date de fin + End date period: Fin (par periode) by_start_date_period: Start date period: Début (par periode) Group by start date evaluations: Grouper les évaluations par semaine/mois/année de la date de début + by_max_date: + Group by max date evaluations: Grouper les évaluations par semaine/mois/année de la date d'échéance + Max date: Date d'échéance + filter: course: by_user_scope: From 03e765f811336e61dc0786b7be7218d38dbbed98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 3 Nov 2022 12:39:19 +0100 Subject: [PATCH 58/99] DX: [export] review on CreatorFilter, CreatorJobAggregator, CreatorJobFilter --- .../CreatorJobAggregator.php | 6 ++--- .../CreatorFilter.php | 25 +++++-------------- .../CreatorJobFilter.php | 1 + .../translations/messages.fr.yml | 2 ++ 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index 3bae64fec..6c958ca6c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -62,15 +62,13 @@ class CreatorJobAggregator implements AggregatorInterface { return function ($value): string { if ('_header' === $value) { - return 'Job'; + return 'export.aggregator.course.by_creator_job.Creator\'s job'; } - if (null === $value) { + if (null === $value || null === $j = $this->jobRepository->find($value)) { return ''; } - $j = $this->jobRepository->find($value); - return $this->translatableStringHelper->localize( $j->getLabel() ); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php index 1ac6d5390..b13947e60 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -11,10 +11,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\PersonBundle\Export\Declarations; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -32,17 +32,9 @@ class CreatorFilter implements FilterInterface $qb->join('acp.createdBy', 'acp_creator'); } - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->in('acp_creator', ':creators'); - - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('creators', $data['accepted_creators']); + $qb + ->andWhere($qb->expr()->in('acp_creator', ':creators')) + ->setParameter('creators', $data['accepted_creators']); } public function applyOn(): string @@ -55,20 +47,15 @@ class CreatorFilter implements FilterInterface $builder ->add('accepted_creators', PickUserDynamicType::class, [ 'multiple' => true, + 'label' => false, ]); } public function describeAction($data, $format = 'string'): array { - $creators = []; - - foreach ($data['accepted_creators'] as $c) { - $creators[] = $c; - } - return [ 'Filtered by creator: only %creators%', [ - '%creators%' => implode(', ', $creators), + '%creators%' => implode(', ', array_map(static fn (User $u) => $u->getLabel(), $data['accepted_creators'])), ], ]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index c8b7ccc55..62cf49d6d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -68,6 +68,7 @@ class CreatorJobFilter implements FilterInterface }, 'multiple' => true, 'expanded' => true, + 'label' => 'Job', ]); } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index dca6c91f6..bdedea895 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1008,6 +1008,8 @@ export: Calc date: Date de calcul de la composition du ménage by_number_of_action: Number of actions: Nombre d'actions + by_creator_job: + Creator's job: Métier du créateur course_work: by_current_action: Current action ?: Action en cours ? From 6fd75a175f2984c4891517f7f30a663435cd1c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 3 Nov 2022 13:59:16 +0100 Subject: [PATCH 59/99] Fixed: [export] improve memory footprint for filter by Geographical Unit --- .../SimpleGeographicalUnitDTO.php | 52 +++++++++++++++++++ .../Export/Helper/ExportAddressHelper.php | 1 + .../Repository/GeographicalUnitRepository.php | 2 +- .../GeographicalUnitStatFilter.php | 24 +++++---- .../PersonFilters/GeographicalUnitFilter.php | 24 +++++---- 5 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php new file mode 100644 index 000000000..34f16a0fb --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php @@ -0,0 +1,52 @@ +id = $id; + $this->unitName = $unitName; + $this->unitRefId = $unitRefId; + $this->layerId = $layerId; + } +} diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 7d4245aa6..701f9ed07 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -205,6 +205,7 @@ class ExportAddressHelper case 'floor': case '_lat': case '_lon': + case 'steps': case 'postcode_code': case 'postcode_name': return static function ($value) use ($sanitizedKey, $translationPrefix) { diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php index 17d29356b..b422b8649 100644 --- a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php @@ -41,7 +41,7 @@ class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface { return $this->repository ->createQueryBuilder('gu') - ->select('PARTIAL gu.{id,unitName,unitRefId,layer}') + ->select(sprintf('NEW %s(gu.id, gu.unitName, gu.unitRefId, IDENTITY(gu.layer))', GeographicalUnit\SimpleGeographicalUnitDTO::class)) ->addOrderBy('IDENTITY(gu.layer)') ->addOrderBy(('gu.unitName')) ->getQuery() diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php index a1347ca99..ee420e63e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php @@ -13,8 +13,10 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\GeographicalUnit; +use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; @@ -23,7 +25,7 @@ use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; /** @@ -33,6 +35,8 @@ class GeographicalUnitStatFilter implements FilterInterface { private EntityManagerInterface $em; + private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; + private GeographicalUnitRepositoryInterface $geographicalUnitRepository; private TranslatableStringHelperInterface $translatableStringHelper; @@ -40,10 +44,12 @@ class GeographicalUnitStatFilter implements FilterInterface public function __construct( EntityManagerInterface $em, GeographicalUnitRepositoryInterface $geographicalUnitRepository, + GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, TranslatableStringHelperInterface $translatableStringHelper ) { $this->em = $em; $this->geographicalUnitRepository = $geographicalUnitRepository; + $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; } @@ -62,7 +68,7 @@ class GeographicalUnitStatFilter implements FilterInterface WITH IDENTITY(acp_geog_filter_location_history.personLocation) = IDENTITY(acp_geog_filter_address_person_location.person) LEFT JOIN ' . Address::class . ' acp_geog_filter_address WITH COALESCE(IDENTITY(acp_geog_filter_address_person_location.address), IDENTITY(acp_geog_filter_location_history.addressLocation)) = acp_geog_filter_address.id - LEFT JOIN ' . GeographicalUnit::class . ' acp_geog_filter_units WITH ST_CONTAINS(acp_geog_units.geom, acp_geog_filter_address.point) = TRUE + LEFT JOIN ' . GeographicalUnit::class . ' acp_geog_filter_units WITH ST_CONTAINS(acp_geog_filter_units.geom, acp_geog_filter_address.point) = TRUE WHERE (acp_geog_filter_location_history.startDate <= :acp_geog_filter_date AND ( acp_geog_filter_location_history.endDate IS NULL OR acp_geog_filter_location_history.endDate < :acp_geog_filter_date @@ -78,7 +84,7 @@ class GeographicalUnitStatFilter implements FilterInterface $qb ->andWhere($qb->expr()->exists($subQueryDql)) ->setParameter('acp_geog_filter_date', $data['date_calc']) - ->setParameter('acp_geog_filter_units', $data['units']); + ->setParameter('acp_geog_filter_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); } public function applyOn(): string @@ -95,13 +101,13 @@ class GeographicalUnitStatFilter implements FilterInterface 'data' => new DateTimeImmutable('today'), 'input' => 'datetime_immutable', ]) - ->add('units', EntityType::class, [ + ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', 'placeholder' => 'Select a geographical unit', - 'class' => GeographicalUnit::class, 'choices' => $this->geographicalUnitRepository->findAll(), - 'choice_label' => function (GeographicalUnit $item) { - return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); + 'choice_value' => static fn (SimpleGeographicalUnitDTO $item) => $item->id, + 'choice_label' => function (SimpleGeographicalUnitDTO $item) { + return $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()) . ' > ' . $item->unitName; }, 'attr' => [ 'class' => 'select2', @@ -117,8 +123,8 @@ class GeographicalUnitStatFilter implements FilterInterface '%units' => implode( ', ', array_map( - function (GeographicalUnit $item) { - return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); + function (SimpleGeographicalUnitDTO $item) { + return $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()) . ' > ' . $item->unitName; }, $data['units'] ) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php index 96a9f5a1c..03d9ab568 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php @@ -12,27 +12,33 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Entity\GeographicalUnit; +use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface { + private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; + private GeographicalUnitRepositoryInterface $geographicalUnitRepository; private TranslatableStringHelperInterface $translatableStringHelper; public function __construct( GeographicalUnitRepositoryInterface $geographicalUnitRepository, + GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, TranslatableStringHelperInterface $translatableStringHelper ) { $this->geographicalUnitRepository = $geographicalUnitRepository; + $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; } @@ -65,7 +71,7 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface $qb->expr()->exists($subQuery) ) ->setParameter('person_filter_geog_date', $data['date_calc']) - ->setParameter('person_filter_geog_units', $data['units']); + ->setParameter('person_filter_geog_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); } public function applyOn() @@ -82,13 +88,13 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface 'data' => new DateTimeImmutable('today'), 'input' => 'datetime_immutable', ]) - ->add('units', EntityType::class, [ + ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', 'placeholder' => 'Select a geographical unit', - 'class' => GeographicalUnit::class, 'choices' => $this->geographicalUnitRepository->findAll(), - 'choice_label' => function (GeographicalUnit $item) { - return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); + 'choice_value' => static fn (SimpleGeographicalUnitDTO $item) => $item->id, + 'choice_label' => function (SimpleGeographicalUnitDTO $item) { + return $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()) . ' > ' . $item->unitName; }, 'attr' => [ 'class' => 'select2', @@ -106,10 +112,10 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface 'units' => implode( ', ', array_map( - function (GeographicalUnit $item) { - return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); + function (SimpleGeographicalUnitDTO $item) { + return $this->translatableStringHelper->localize($this->geographicalUnitLayerRepository->find($item->layerId)->getName()) . ' > ' . $item->unitName; }, - $data['units']->toArray() + $data['units'] ) ), ], From 5489178e4b9c70d3de9e49489a6c352977029818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 14:06:47 +0100 Subject: [PATCH 60/99] DX: Create a RollingDate data transfer object and Form type --- .../Form/DataMapper/RollingDateDataMapper.php | 45 ++++++++ .../Form/Type/PickRollingDateType.php | 50 +++++++++ .../Service/RollingDate/RollingDate.php | 101 ++++++++++++++++++ .../Form/Type/PickRollingDateTypeTest.php | 53 +++++++++ .../translations/messages.fr.yml | 19 ++++ 5 files changed, 268 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php create mode 100644 src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php create mode 100644 src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Form/Type/PickRollingDateTypeTest.php diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php new file mode 100644 index 000000000..21d0c3fde --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php @@ -0,0 +1,45 @@ +setData($viewData->getRoll()); + $forms['fixedDate']->setData($viewData->getFixedDate()); + } + + public function mapFormsToData($forms, &$viewData): void + { + $forms = iterator_to_array($forms); + + $viewData = new RollingDate( + $forms['roll']->getData(), + $forms['fixedDate']->getData() + ); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php new file mode 100644 index 000000000..a54dc778b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php @@ -0,0 +1,50 @@ +add('roll', ChoiceType::class, [ + 'choices' => array_combine( + array_map(static fn (string $item) => 'rolling_date.' . $item, RollingDate::ALL_T), + RollingDate::ALL_T + ), + 'multiple' => false, + 'expanded' => false, + 'label' => 'rolling_date.roll_movement', + ]) + ->add('fixedDate', ChillDateType::class, [ + 'input' => 'datetime_immutable', + 'label' => 'rolling_date.fixed_date_date', + ]); + + $builder->setDataMapper(new RollingDateDataMapper()); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'class' => RollingDate::class, + 'empty_data' => new RollingDate(RollingDate::T_TODAY), + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php new file mode 100644 index 000000000..cc00c7777 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php @@ -0,0 +1,101 @@ +roll = $roll; + $this->pivotDate = $pivotDate ?? new DateTimeImmutable('now'); + $this->fixedDate = $fixedDate; + } + + public function getFixedDate(): DateTimeImmutable + { + return $this->fixedDate; + } + + public function getPivotDate(): ?DateTimeImmutable + { + return $this->pivotDate; + } + + public function getRoll(): string + { + return $this->roll; + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Form/Type/PickRollingDateTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/PickRollingDateTypeTest.php new file mode 100644 index 000000000..771dd0310 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/PickRollingDateTypeTest.php @@ -0,0 +1,53 @@ + 'year_previous_start', + 'fixedDate' => null, + ]; + + $form = $this->factory->create(PickRollingDateType::class); + + $form->submit($formData); + + $this->assertTrue($form->isSynchronized()); + + /** @var RollingDate $rollingDate */ + $rollingDate = $form->getData(); + + $this->assertInstanceOf(RollingDate::class, $rollingDate); + $this->assertEquals(RollingDate::T_YEAR_PREVIOUS_START, $rollingDate->getRoll()); + } + + protected function getExtensions(): array + { + $type = new PickRollingDateType(); + + return [ + new PreloadedExtension([$type], []), + ]; + } +} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 3e229b8d4..c532ba30f 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -538,3 +538,22 @@ export: isNoAddress: Adresse incomplète ? _lat: Latitude _lon: Longitude + +rolling_date: + year_previous_start: Début de l'année précédente + quarter_previous_start: Début du trimestre précédent + month_previous_start: Début du mois précédent + week_previous_start: Début de la semaine précédente + year_current_start: Début de l'année courante + quarter_current_start: Début du trimestre courant + month_current_start: Début du mois courant + week_current_start: Début de la semaine courante + today: Aujourd'hui (aucune modification de la date courante) + year_next_start: Début de l'année suivante + quarter_next_start: Début du trimestre suivante + month_next_start: Début du mois suivant + week_next_start: Début de la semaine suivante + fixed_date: Date fixe + roll_movement: Modification par rapport à aujourd'hui + fixed_date_date: Date fixe + From c7f740d5d7e48a3cc1af34bc36b7f546f30f604b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 17:42:00 +0100 Subject: [PATCH 61/99] DX: Add rolling date converter + unit test --- .../Service/RollingDate/RollingDate.php | 2 +- .../RollingDate/RollingDateConverter.php | 141 ++++++++++++++++++ .../RollingDate/RollingDateConverterTest.php | 101 +++++++++++++ 3 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php index cc00c7777..7294e6816 100644 --- a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php @@ -77,7 +77,7 @@ class RollingDate * @param DateTimeImmutable|null $pivotDate Will be "now" if null is given * @param DateTimeImmutable|null $fixedDate Only to insert if $roll equals @see{self::T_FIXED_DATE} */ - public function __construct(string $roll, ?DateTimeImmutable $pivotDate = null, ?DateTimeImmutable $fixedDate = null) + public function __construct(string $roll, ?DateTimeImmutable $fixedDate = null, ?DateTimeImmutable $pivotDate = null) { $this->roll = $roll; $this->pivotDate = $pivotDate ?? new DateTimeImmutable('now'); diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php new file mode 100644 index 000000000..e3cfb8e89 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php @@ -0,0 +1,141 @@ +getRoll()) { + case RollingDate::T_MONTH_CURRENT_START: + return $this->toBeginOfMonth($rollingDate->getPivotDate()); + + case RollingDate::T_MONTH_NEXT_START: + return $this->toBeginOfMonth($rollingDate->getPivotDate()->add(new DateInterval('P1M'))); + + case RollingDate::T_MONTH_PREVIOUS_START: + return $this->toBeginOfMonth($rollingDate->getPivotDate()->sub(new DateInterval('P1M'))); + + case RollingDate::T_QUARTER_CURRENT_START: + return $this->toBeginOfQuarter($rollingDate->getPivotDate()); + + case RollingDate::T_QUARTER_NEXT_START: + return $this->toBeginOfQuarter($rollingDate->getPivotDate()->add(new DateInterval('P3M'))); + + case RollingDate::T_QUARTER_PREVIOUS_START: + return $this->toBeginOfQuarter($rollingDate->getPivotDate()->sub(new DateInterval('P3M'))); + + case RollingDate::T_WEEK_CURRENT_START: + return $this->toBeginOfWeek($rollingDate->getPivotDate()); + + case RollingDate::T_WEEK_NEXT_START: + return $this->toBeginOfWeek($rollingDate->getPivotDate()->add(new DateInterval('P1W'))); + + case RollingDate::T_WEEK_PREVIOUS_START: + return $this->toBeginOfWeek($rollingDate->getPivotDate()->sub(new DateInterval('P1W'))); + + case RollingDate::T_YEAR_CURRENT_START: + return $this->toBeginOfYear($rollingDate->getPivotDate()); + + case RollingDate::T_YEAR_PREVIOUS_START: + return $this->toBeginOfYear($rollingDate->getPivotDate()->sub(new DateInterval('P1Y'))); + + case RollingDate::T_YEAR_NEXT_START: + return $this->toBeginOfYear($rollingDate->getPivotDate()->add(new DateInterval('P1Y'))); + + case RollingDate::T_TODAY: + return $rollingDate->getPivotDate(); + + case RollingDate::T_FIXED_DATE: + if (null === $rollingDate->getFixedDate()) { + throw new \LogicException("You must provide a fixed date when selecting a fixed date"); + } + return $rollingDate->getFixedDate(); + + default: + throw new UnexpectedValueException(sprintf('%s rolling operation not supported', $rollingDate->getRoll())); + } + } + + private function toBeginOfMonth(DateTimeImmutable $date): DateTimeImmutable + { + return DateTimeImmutable::createFromFormat( + 'Y-m-d His', + sprintf('%s-%s-01 000000', $date->format('Y'), $date->format('m')) + ); + } + + private function toBeginOfQuarter(DateTimeImmutable $date): DateTimeImmutable + { + switch ((int) $date->format('n')) { + case 1: + case 2: + case 3: + $month = '01'; + + break; + + case 4: + case 5: + case 6: + $month = '04'; + + break; + + case 7: + case 8: + case 9: + $month = '07'; + + break; + + case 10: + case 11: + case 12: + $month = '10'; + + break; + + default: + throw new LogicException('this month is not valid: ' . $date->format('n')); + } + + return DateTimeImmutable::createFromFormat( + 'Y-m-d His', + sprintf('%s-%s-01 000000', $date->format('Y'), $month) + ); + } + + private function toBeginOfWeek(DateTimeImmutable $date): DateTimeImmutable + { + if (1 === $dayOfWeek = (int) $date->format('N')) { + return $date->setTime(0, 0, 0); + } + + return $date + ->sub(new DateInterval('P' . ($dayOfWeek - 1) . 'D')) + ->setTime(0, 0, 0); + } + + private function toBeginOfYear(DateTimeImmutable $date): DateTimeImmutable + { + return DateTimeImmutable::createFromFormat( + 'Y-m-d His', + sprintf('%s-01-01 000000', $date->format('Y')) + ); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php b/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php new file mode 100644 index 000000000..6df2c889b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Services/RollingDate/RollingDateConverterTest.php @@ -0,0 +1,101 @@ +converter = new RollingDateConverter(); + } + + public function generateDataConversionDate(): iterable + { + $format = 'Y-m-d His'; + + yield [RollingDate::T_MONTH_CURRENT_START, '2022-11-01 000000', $format]; + + yield [RollingDate::T_MONTH_NEXT_START, '2022-12-01 000000', $format]; + + yield [RollingDate::T_MONTH_PREVIOUS_START, '2022-10-01 000000', $format]; + + yield [RollingDate::T_QUARTER_CURRENT_START, '2022-10-01 000000', $format]; + + yield [RollingDate::T_QUARTER_NEXT_START, '2023-01-01 000000', $format]; + + yield [RollingDate::T_QUARTER_PREVIOUS_START, '2022-07-01 000000', $format]; + + yield [RollingDate::T_TODAY, '2022-11-07 000000', $format]; + + yield [RollingDate::T_WEEK_CURRENT_START, '2022-11-07 000000', $format]; + + yield [RollingDate::T_WEEK_NEXT_START, '2022-11-14 000000', $format]; + + yield [RollingDate::T_WEEK_PREVIOUS_START, '2022-10-31 000000', $format]; + + yield [RollingDate::T_YEAR_CURRENT_START, '2022-01-01 000000', $format]; + + yield [RollingDate::T_YEAR_NEXT_START, '2023-01-01 000000', $format]; + + yield [RollingDate::T_YEAR_PREVIOUS_START, '2021-01-01 000000', $format]; + } + + public function testConversionFixedDate() + { + $rollingDate = new RollingDate(RollingDate::T_FIXED_DATE, new DateTimeImmutable('2022-01-01')); + + $this->assertEquals( + '2022-01-01', + $this->converter->convert($rollingDate)->format('Y-m-d') + ); + } + + public function testConvertOnDateNow() + { + $rollingDate = new RollingDate(RollingDate::T_YEAR_PREVIOUS_START); + + $actual = $this->converter->convert($rollingDate); + + $this->assertEquals( + (int) (new DateTimeImmutable('now'))->format('Y') - 1, + (int) $actual->format('Y') + ); + $this->assertEquals(1, (int) $actual->format('m')); + $this->assertEquals(1, (int) $actual->format('d')); + } + + /** + * @dataProvider generateDataConversionDate + */ + public function testConvertOnPivotDate(string $roll, string $expectedDateTime, string $format) + { + $pivot = DateTimeImmutable::createFromFormat('Y-m-d His', '2022-11-07 000000'); + $rollingDate = new RollingDate($roll, null, $pivot); + + $this->assertEquals( + DateTime::createFromFormat($format, $expectedDateTime), + $this->converter->convert($rollingDate) + ); + } +} From 4e3c93cdd3b0e244491f8456f58ed85463af1cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 17:56:30 +0100 Subject: [PATCH 62/99] DX: Add validation to PickRolingDateType It is not possible to pick a fixed date when not setting a fixed date --- .../Form/Type/PickRollingDateType.php | 17 +++++++++++++++++ .../Service/RollingDate/RollingDate.php | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php index a54dc778b..a3013f792 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php @@ -17,6 +17,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Context\ExecutionContextInterface; class PickRollingDateType extends AbstractType { @@ -45,6 +47,21 @@ class PickRollingDateType extends AbstractType $resolver->setDefaults([ 'class' => RollingDate::class, 'empty_data' => new RollingDate(RollingDate::T_TODAY), + 'constraints' => [ + new Callback([$this, 'validate']) + ] ]); } + + public function validate($data, ExecutionContextInterface $context, $payload): void + { + /** @var RollingDate $data */ + if (RollingDate::T_FIXED_DATE === $data->getRoll() && null === $data->getFixedDate()) { + $context + ->buildViolation('rolling_date.When fixed date is selected, you must provide a date') + ->atPath('roll') + ->addViolation() + ; + } + } } diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php index 7294e6816..e8427c62f 100644 --- a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDate.php @@ -84,12 +84,12 @@ class RollingDate $this->fixedDate = $fixedDate; } - public function getFixedDate(): DateTimeImmutable + public function getFixedDate(): ?DateTimeImmutable { return $this->fixedDate; } - public function getPivotDate(): ?DateTimeImmutable + public function getPivotDate(): DateTimeImmutable { return $this->pivotDate; } From 0756bec5806bc5b44bc3409c3613487f4cd9c204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 18:07:26 +0100 Subject: [PATCH 63/99] DX: fix cs --- .../Service/RollingDate/RollingDateConverter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php index e3cfb8e89..9ec78c509 100644 --- a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php @@ -62,8 +62,9 @@ class RollingDateConverter case RollingDate::T_FIXED_DATE: if (null === $rollingDate->getFixedDate()) { - throw new \LogicException("You must provide a fixed date when selecting a fixed date"); + throw new LogicException('You must provide a fixed date when selecting a fixed date'); } + return $rollingDate->getFixedDate(); default: From 8159f91e2519e6774696742a2cba559f25627ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 18:19:35 +0100 Subject: [PATCH 64/99] DX: create interface for RollingDateConverterInterface --- .../RollingDate/RollingDateConverter.php | 2 +- .../RollingDateConverterInterface.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverterInterface.php diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php index 9ec78c509..026ff7a8a 100644 --- a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverter.php @@ -16,7 +16,7 @@ use DateTimeImmutable; use LogicException; use UnexpectedValueException; -class RollingDateConverter +class RollingDateConverter implements RollingDateConverterInterface { public function convert(RollingDate $rollingDate): DateTimeImmutable { diff --git a/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverterInterface.php b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverterInterface.php new file mode 100644 index 000000000..b20a5ced2 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/RollingDate/RollingDateConverterInterface.php @@ -0,0 +1,19 @@ + Date: Mon, 7 Nov 2022 18:20:22 +0100 Subject: [PATCH 65/99] Feature: [export] Add a rolling date on Acp "by step" filter --- .../ChillMainBundle/config/services.yaml | 5 ++ .../AccompanyingCourseFilters/StepFilter.php | 59 +++++++++++++------ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/Bundle/ChillMainBundle/config/services.yaml b/src/Bundle/ChillMainBundle/config/services.yaml index 040db1a9f..1c56c1ad5 100644 --- a/src/Bundle/ChillMainBundle/config/services.yaml +++ b/src/Bundle/ChillMainBundle/config/services.yaml @@ -105,3 +105,8 @@ services: resource: '../Service/Import/' autowire: true autoconfigure: true + + Chill\MainBundle\Service\RollingDate\: + resource: '../Service/RollingDate/' + autowire: true + autoconfigure: true diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php index 2eb1b90b3..0c9b28e8c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php @@ -12,31 +12,40 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Export\Declarations; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Contracts\Translation\TranslatorInterface; +use function in_array; class StepFilter implements FilterInterface { + private const A = 'acp_filter_bystep_stephistories'; + private const DEFAULT_CHOICE = AccompanyingPeriod::STEP_CONFIRMED; + private const P = 'acp_step_filter_date'; + private const STEPS = [ 'Draft' => AccompanyingPeriod::STEP_DRAFT, 'Confirmed' => AccompanyingPeriod::STEP_CONFIRMED, 'Closed' => AccompanyingPeriod::STEP_CLOSED, ]; + private RollingDateConverterInterface $rollingDateConverter; + /** * @var TranslatorInterface */ - protected $translator; + private $translator; - public function __construct(TranslatorInterface $translator) + public function __construct(RollingDateConverterInterface $rollingDateConverter, TranslatorInterface $translator) { + $this->rollingDateConverter = $rollingDateConverter; $this->translator = $translator; } @@ -47,17 +56,25 @@ class StepFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->eq('acp.step', ':step'); - - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); + if (!in_array(self::A, $qb->getAllAliases(), true)) { + $qb->leftJoin('acp.stepHistories', self::A); } - $qb->add('where', $where); - $qb->setParameter('step', $data['accepted_steps']); + $qb + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte(self::A . '.startDate', ':' . self::P), + $qb->expr()->orX( + $qb->expr()->isNull(self::A . '.endDate'), + $qb->expr()->lt(self::A . '.endDate', ':' . self::P) + ) + ) + ) + ->andWhere( + $qb->expr()->in(self::A . '.step', ':acp_filter_by_step_steps') + ) + ->setParameter(self::P, $this->rollingDateConverter->convert($data['calc_date'])) + ->setParameter('acp_filter_by_step_steps', $data['accepted_steps']); } public function applyOn() @@ -67,13 +84,17 @@ class StepFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_steps', ChoiceType::class, [ - 'choices' => self::STEPS, - 'multiple' => false, - 'expanded' => true, - 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, - ]); + $builder + ->add('accepted_steps', ChoiceType::class, [ + 'choices' => self::STEPS, + 'multiple' => false, + 'expanded' => true, + 'empty_data' => self::DEFAULT_CHOICE, + 'data' => self::DEFAULT_CHOICE, + ]) + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.acp.filter.by_step.date_calc', + ]); } public function describeAction($data, $format = 'string') From 50db96ffbc3e5f8d3be3fc63cdd473b470823859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 18:20:34 +0100 Subject: [PATCH 66/99] Fix validation of fixed date --- .../ChillMainBundle/Form/Type/PickRollingDateType.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php index a3013f792..2c90379f2 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php @@ -48,8 +48,8 @@ class PickRollingDateType extends AbstractType 'class' => RollingDate::class, 'empty_data' => new RollingDate(RollingDate::T_TODAY), 'constraints' => [ - new Callback([$this, 'validate']) - ] + new Callback([$this, 'validate']), + ], ]); } @@ -60,8 +60,7 @@ class PickRollingDateType extends AbstractType $context ->buildViolation('rolling_date.When fixed date is selected, you must provide a date') ->atPath('roll') - ->addViolation() - ; + ->addViolation(); } } } From 48da6d0a92920a2c5128d9e78b7f7e1e35ca77e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 21:11:20 +0100 Subject: [PATCH 67/99] Feature: Apply rolling date on StepAggregator --- .../StepAggregator.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php index fc2fcc7b2..e17e9f9a5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php @@ -12,10 +12,11 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -27,11 +28,15 @@ final class StepAggregator implements AggregatorInterface private const P = 'acp_step_agg_date'; + private RollingDateConverterInterface $rollingDateConverter; + private TranslatorInterface $translator; public function __construct( + RollingDateConverterInterface $rollingDateConverter, TranslatorInterface $translator ) { + $this->rollingDateConverter = $rollingDateConverter; $this->translator = $translator; } @@ -60,7 +65,7 @@ final class StepAggregator implements AggregatorInterface ) ) ) - ->setParameter(self::P, $data['on_date']) + ->setParameter(self::P, $this->rollingDateConverter->convert($data['on_date'])) ->addGroupBy('step_aggregator'); } @@ -71,8 +76,8 @@ final class StepAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', ChillDateType::class, [ - 'data' => new DateTime(), + $builder->add('on_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } From 8aeeab9e6b876f26b27b831954c80d9ec206c795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 7 Nov 2022 21:18:56 +0100 Subject: [PATCH 68/99] Feature: Apply rolling "open between dates filters" (accompanying period) --- .../OpenBetweenDatesFilter.php | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php index 5b8335c55..07ca1de75 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php @@ -12,15 +12,23 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class OpenBetweenDatesFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -34,8 +42,8 @@ class OpenBetweenDatesFilter implements FilterInterface ); $qb->andWhere($clause); - $qb->setParameter('datefrom', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('dateto', $data['date_to'], Types::DATE_MUTABLE); + $qb->setParameter('datefrom', $this->rollingDateConverter->convert($data['date_from']), Types::DATE_IMMUTABLE); + $qb->setParameter('dateto', $this->rollingDateConverter->convert($data['date_to']), Types::DATE_IMMUTABLE); } public function applyOn(): string @@ -46,19 +54,19 @@ class OpenBetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_from', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_MONTH_PREVIOUS_START), ]) - ->add('date_to', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_to', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by opening dates: between %datefrom% and %dateto%', [ - '%datefrom%' => $data['date_from']->format('d-m-Y'), - '%dateto%' => $data['date_to']->format('d-m-Y'), + '%datefrom%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%dateto%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ]]; } From ccb2cd029563df5f194e3e8ba4a1126164c7e2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Nov 2022 10:20:38 +0100 Subject: [PATCH 69/99] Feature: [saved export] Create a "saved export" --- .../Controller/ExportController.php | 115 +++++++++++---- .../ChillMainBundle/Entity/SavedExport.php | 133 ++++++++++++++++++ .../ChillMainBundle/Form/SavedExportType.php | 40 ++++++ .../Resources/views/Export/download.html.twig | 4 + .../Resources/views/SavedExport/new.html.twig | 21 +++ .../migrations/Version20221107212201.php | 43 ++++++ .../translations/messages.fr.yml | 2 + 7 files changed, 329 insertions(+), 29 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Entity/SavedExport.php create mode 100644 src/Bundle/ChillMainBundle/Form/SavedExportType.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20221107212201.php diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 96c9ed08d..9037ae141 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -11,11 +11,15 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; +use Chill\MainBundle\Entity\SavedExport; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Form\SavedExportType; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\FormatterType; use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Redis\ChillRedis; +use Doctrine\ORM\EntityManagerInterface; use LogicException; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -26,6 +30,8 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\Routing\Annotation\Route; use Symfony\Contracts\Translation\TranslatorInterface; use function count; @@ -38,35 +44,37 @@ use function unserialize; */ class ExportController extends AbstractController { + private EntityManagerInterface $entityManager; + /** * @var ExportManager */ - protected $exportManager; + private $exportManager; /** * @var FormFactoryInterface */ - protected $formFactory; + private $formFactory; /** * @var LoggerInterface */ - protected $logger; + private $logger; /** * @var ChillRedis */ - protected $redis; + private $redis; /** * @var SessionInterface */ - protected $session; + private $session; /** * @var TranslatorInterface */ - protected $translator; + private $translator; public function __construct( ChillRedis $chillRedis, @@ -74,8 +82,10 @@ class ExportController extends AbstractController FormFactoryInterface $formFactory, LoggerInterface $logger, SessionInterface $session, - TranslatorInterface $translator + TranslatorInterface $translator, + EntityManagerInterface $entityManager ) { + $this->entityManager = $entityManager; $this->redis = $chillRedis; $this->exportManager = $exportManager; $this->formFactory = $formFactory; @@ -203,6 +213,46 @@ class ExportController extends AbstractController } } + /** + * @Route("/{_locale}/export/save-from-key/{alias}/{key}", name="chill_main_export_save_from_key") + */ + public function saveFromKey(string $alias, string $key, Request $request): Response + { + $this->denyAccessUnlessGranted('ROLE_USER'); + $user = $this->getUser(); + + if (!$user instanceof User) { + throw new AccessDeniedHttpException(); + } + + $data = $this->rebuildRawData($key); + + $savedExport = new SavedExport(); + $savedExport + ->setOptions($data) + ->setExportAlias($alias) + ->setUser($user); + + $form = $this->createForm(SavedExportType::class, $savedExport); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->persist($savedExport); + $this->entityManager->flush(); + + return $this->redirectToRoute('chill_main_export_index'); + } + + return $this->render( + '@ChillMain/SavedExport/new.html.twig', + [ + 'form' => $form->createView(), + 'saved_export' => $savedExport, + ] + ); + } + /** * create a form to show on different steps. * @@ -418,28 +468,7 @@ class ExportController extends AbstractController protected function rebuildData($key) { - if (null === $key) { - throw $this->createNotFoundException('key does not exists'); - } - - if ($this->redis->exists($key) !== 1) { - $this->addFlash('error', $this->translator->trans('This report is not available any more')); - - throw $this->createNotFoundException('key does not exists'); - } - - $serialized = $this->redis->get($key); - - if (false === $serialized) { - throw new LogicException('the key could not be reached from redis'); - } - - $rawData = unserialize($serialized); - - $this->logger->notice('[export] choices for an export unserialized', [ - 'key' => $key, - 'rawData' => json_encode($rawData), - ]); + $rawData = $this->rebuildRawData($key); $alias = $rawData['alias']; @@ -585,4 +614,32 @@ class ExportController extends AbstractController throw new LogicException("the step {$step} is not defined."); } } + + private function rebuildRawData(string $key): array + { + if (null === $key) { + throw $this->createNotFoundException('key does not exists'); + } + + if ($this->redis->exists($key) !== 1) { + $this->addFlash('error', $this->translator->trans('This report is not available any more')); + + throw $this->createNotFoundException('key does not exists'); + } + + $serialized = $this->redis->get($key); + + if (false === $serialized) { + throw new LogicException('the key could not be reached from redis'); + } + + $rawData = unserialize($serialized); + + $this->logger->notice('[export] choices for an export unserialized', [ + 'key' => $key, + 'rawData' => json_encode($rawData), + ]); + + return $rawData; + } } diff --git a/src/Bundle/ChillMainBundle/Entity/SavedExport.php b/src/Bundle/ChillMainBundle/Entity/SavedExport.php new file mode 100644 index 000000000..3ac361e81 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/SavedExport.php @@ -0,0 +1,133 @@ +id = Uuid::uuid4(); + } + + public function getDescription(): string + { + return $this->description; + } + + public function getExportAlias(): string + { + return $this->exportAlias; + } + + public function getId(): UuidInterface + { + return $this->id; + } + + public function getOptions(): array + { + return $this->options; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getUser(): User + { + return $this->user; + } + + public function setDescription(string $description): SavedExport + { + $this->description = $description; + + return $this; + } + + public function setExportAlias(string $exportAlias): SavedExport + { + $this->exportAlias = $exportAlias; + + return $this; + } + + public function setOptions(array $options): SavedExport + { + $this->options = $options; + + return $this; + } + + public function setTitle(string $title): SavedExport + { + $this->title = $title; + + return $this; + } + + public function setUser(User $user): SavedExport + { + $this->user = $user; + + return $this; + } +} diff --git a/src/Bundle/ChillMainBundle/Form/SavedExportType.php b/src/Bundle/ChillMainBundle/Form/SavedExportType.php new file mode 100644 index 000000000..16aa4e42e --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/SavedExportType.php @@ -0,0 +1,40 @@ +add('title', TextType::class, [ + 'required' => true, + ]) + ->add('description', ChillTextareaType::class, [ + 'required' => false, + ]); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'class' => SavedExport::class, + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig index 84eb85100..a15e60088 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig @@ -49,5 +49,9 @@ window.addEventListener("DOMContentLoaded", function(e) { data-download-text="{{ "Download your report"|trans|escape('html_attr') }}" >{{ "Waiting for your report"|trans ~ '...' }} + + {% endblock content %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig new file mode 100644 index 000000000..037adb0fc --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig @@ -0,0 +1,21 @@ +{% extends "@ChillMain/layout.html.twig" %} + +{% block title %}{{ 'saved_export.New'|trans }}{% endblock %} + +{% block content %} +

{{ block('title') }}

+ + {{ form_start(form) }} + {{ form_row(form.title) }} + {{ form_row(form.description) }} + + + {{ form_end(form) }} +{% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/migrations/Version20221107212201.php b/src/Bundle/ChillMainBundle/migrations/Version20221107212201.php new file mode 100644 index 000000000..58285c333 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20221107212201.php @@ -0,0 +1,43 @@ +addSql('DROP TABLE chill_main_saved_export'); + } + + public function getDescription(): string + { + return 'Create table for saved exports'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE TABLE chill_main_saved_export (id UUID NOT NULL, user_id INT DEFAULT NULL, description TEXT DEFAULT \'\' NOT NULL, exportAlias TEXT DEFAULT \'\' NOT NULL, options JSONB DEFAULT \'[]\' NOT NULL, title TEXT DEFAULT \'\' NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_C2029B22A76ED395 ON chill_main_saved_export (user_id)'); + $this->addSql('CREATE INDEX IDX_C2029B223174800F ON chill_main_saved_export (createdBy_id)'); + $this->addSql('CREATE INDEX IDX_C2029B2265FF1AEC ON chill_main_saved_export (updatedBy_id)'); + $this->addSql('COMMENT ON COLUMN chill_main_saved_export.id IS \'(DC2Type:uuid)\''); + $this->addSql('COMMENT ON COLUMN chill_main_saved_export.options IS \'(DC2Type:json)\''); + $this->addSql('COMMENT ON COLUMN chill_main_saved_export.createdAt IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_main_saved_export.updatedAt IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE chill_main_saved_export ADD CONSTRAINT FK_C2029B22A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_main_saved_export ADD CONSTRAINT FK_C2029B223174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_main_saved_export ADD CONSTRAINT FK_C2029B2265FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } +} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index c532ba30f..42f1c8004 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -557,3 +557,5 @@ rolling_date: roll_movement: Modification par rapport à aujourd'hui fixed_date_date: Date fixe +saved_export: + New: Nouveau rapport enregistré From aec4c52567efd99858ec80d478a5eb041504bb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Nov 2022 16:57:49 +0100 Subject: [PATCH 70/99] Feature: [saved export] First list of saved exports --- .../Controller/SavedExportController.php | 90 +++++++++++++++++++ .../Repository/SavedExportRepository.php | 82 +++++++++++++++++ .../SavedExportRepositoryInterface.php | 40 +++++++++ .../views/SavedExport/index.html.twig | 49 ++++++++++ .../translations/messages.fr.yml | 1 + 5 files changed, 262 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/Controller/SavedExportController.php create mode 100644 src/Bundle/ChillMainBundle/Repository/SavedExportRepository.php create mode 100644 src/Bundle/ChillMainBundle/Repository/SavedExportRepositoryInterface.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig diff --git a/src/Bundle/ChillMainBundle/Controller/SavedExportController.php b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php new file mode 100644 index 000000000..051fa5231 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php @@ -0,0 +1,90 @@ +exportManager = $exportManager; + $this->savedExportRepository = $savedExportRepository; + $this->security = $security; + $this->templating = $templating; + $this->translator = $translator; + } + + /** + * @Route("/{_locale}/exports/saved/my", name="chill_main_export_saved_list_my") + */ + public function list(): Response + { + $user = $this->security->getUser(); + + if (!$this->security->isGranted('ROLE_USER') || !$user instanceof User) { + throw new AccessDeniedHttpException(); + } + + $exports = $this->savedExportRepository->findByUser($user, ['title' => 'ASC']); + + // group by center + /** @var array $exportsGrouped */ + $exportsGrouped = []; + + foreach ($exports as $savedExport) { + $export = $this->exportManager->getExport($savedExport->getExportAlias()); + + $exportsGrouped[ + $export instanceof GroupedExportInterface + ? $this->translator->trans($export->getGroup()) : '_' + ][] = ['saved' => $savedExport, 'export' => $export]; + } + + ksort($exportsGrouped); + + return new Response( + $this->templating->render( + '@ChillMain/SavedExport/index.html.twig', + [ + 'grouped_exports' => $exportsGrouped, + ] + ) + ); + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/SavedExportRepository.php b/src/Bundle/ChillMainBundle/Repository/SavedExportRepository.php new file mode 100644 index 000000000..0011c5c43 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/SavedExportRepository.php @@ -0,0 +1,82 @@ + + */ +class SavedExportRepository implements SavedExportRepositoryInterface +{ + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->repository = $entityManager->getRepository($this->getClassName()); + } + + public function find($id): ?SavedExport + { + return $this->repository->find($id); + } + + /** + * @return array|SavedExport[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findByUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array + { + $qb = $this->repository->createQueryBuilder('se'); + + $qb + ->where($qb->expr()->eq('se.user', ':user')) + ->setParameter('user', $user); + + if (null !== $limit) { + $qb->setMaxResults($limit); + } + + if (null !== $offset) { + $qb->setFirstResult($offset); + } + + foreach ($orderBy as $field => $order) { + $qb->addOrderBy('se.' . $field, $order); + } + + return $qb->getQuery()->getResult(); + } + + public function findOneBy(array $criteria): ?SavedExport + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return SavedExport::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/SavedExportRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/SavedExportRepositoryInterface.php new file mode 100644 index 000000000..3b168505f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/SavedExportRepositoryInterface.php @@ -0,0 +1,40 @@ + + */ +interface SavedExportRepositoryInterface extends ObjectRepository +{ + public function find($id): ?SavedExport; + + /** + * @return array|SavedExport[] + */ + public function findAll(): array; + + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array; + + /** + * @return array|SavedExport[] + */ + public function findByUser(User $user, ?array $orderBy = [], ?int $limit = null, ?int $offset = null): array; + + public function findOneBy(array $criteria): ?SavedExport; + + public function getClassName(): string; +} diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig new file mode 100644 index 000000000..071a177a5 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -0,0 +1,49 @@ +{% extends "@ChillMain/layout.html.twig" %} + +{% block title %}{{ 'saved_export.My saved exports'|trans }}{% endblock %} + +{% block content %} +
+

{{ block('title') }}

+ +
+ + {% for group, saveds in grouped_exports %} + {% if group != '_' %} +

{{ group }}

+
+ {% for s in saveds %} +
+

{{ s.saved.title }}

+

{{ s.export.title|trans }}

+
+ {{ s.saved.description|chill_markdown_to_html }} +
+
+ {% endfor %} +
+ {% endif %} + {% endfor %} + + {% if grouped_exports|keys|length > 1 and grouped_exports['_']|length > 0 %} +

{{ 'Ungrouped exports'|trans }}

+ {% endif %} + +
+ {% for saveds in grouped_exports['_']|default([]) %} + {% for s in saveds %} +
+
+

{{ s.saved.title }}

+

{{ s.export.title|trans }}

+
+ {{ s.saved.description|chill_markdown_to_html }} +
+
+
+ {% endfor %} + {% endfor %} +
+
+
+{% endblock %} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 42f1c8004..498f185b6 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -559,3 +559,4 @@ rolling_date: saved_export: New: Nouveau rapport enregistré + My saved exports: Mes rapports enregistrés From 79e9906a053813b3e7c33ba5e95977de3eaf36bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Nov 2022 18:02:26 +0100 Subject: [PATCH 71/99] =?UTF-8?q?Feature:=20[saved=20export]=20G=C3=A9n?= =?UTF-8?q?=C3=A9rate=20a=20report=20from=20a=20saved=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/ExportController.php | 24 +++++++++++- .../Resources/views/Export/download.html.twig | 13 +++++-- .../views/SavedExport/index.html.twig | 14 ++++++- .../Authorization/SavedExportVoter.php | 39 +++++++++++++++++++ .../config/services/security.yaml | 2 + 5 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 9037ae141..293a3c778 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -19,21 +19,24 @@ use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\FormatterType; use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Redis\ChillRedis; +use Chill\MainBundle\Security\Authorization\SavedExportVoter; use Doctrine\ORM\EntityManagerInterface; use LogicException; use Psr\Log\LoggerInterface; +use RedisException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; use function count; use function serialize; use function unserialize; @@ -152,6 +155,25 @@ class ExportController extends AbstractController ); } + /** + * @Route("/{_locale}/exports/generate-from-saved/{id}", name="chill_main_export_generate_from_saved") + * + * @throws RedisException + */ + public function generateFromSavedExport(SavedExport $savedExport): RedirectResponse + { + $this->denyAccessUnlessGranted(SavedExportVoter::GENERATE, $savedExport); + + $key = md5(uniqid((string) mt_rand(), false)); + + $this->redis->setEx($key, 3600, serialize($savedExport->getOptions())); + + return $this->redirectToRoute( + 'chill_main_export_download', + ['alias' => $savedExport->getExportAlias(), 'key' => $key, 'prevent_save' => true] + ); + } + /** * Render the list of available exports. */ diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig index a15e60088..1e69c5a49 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig @@ -49,9 +49,14 @@ window.addEventListener("DOMContentLoaded", function(e) { data-download-text="{{ "Download your report"|trans|escape('html_attr') }}" >{{ "Waiting for your report"|trans ~ '...' }} - + + {% endblock content %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index 071a177a5..5cd697bb4 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -15,10 +15,16 @@ {% for s in saveds %}

{{ s.saved.title }}

-

{{ s.export.title|trans }}

+

{{ s.export.title|trans }}

{{ s.saved.description|chill_markdown_to_html }}
+ +
    +
  • +
  • +
  • +
{% endfor %} @@ -39,6 +45,12 @@
{{ s.saved.description|chill_markdown_to_html }}
+ +
    +
  • +
  • +
  • +
{% endfor %} diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php new file mode 100644 index 000000000..bc74e2d45 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php @@ -0,0 +1,39 @@ +getUser() === $token->getUser(); + + default: + throw new UnexpectedValueException('attribute not supported: ' . $attribute); + } + } +} diff --git a/src/Bundle/ChillMainBundle/config/services/security.yaml b/src/Bundle/ChillMainBundle/config/services/security.yaml index 3347871e3..824144470 100644 --- a/src/Bundle/ChillMainBundle/config/services/security.yaml +++ b/src/Bundle/ChillMainBundle/config/services/security.yaml @@ -50,6 +50,8 @@ services: tags: - { name: security.voter } + Chill\MainBundle\Security\Authorization\SavedExportVoter: ~ + Chill\MainBundle\Security\PasswordRecover\TokenManager: arguments: $secret: '%kernel.secret%' From 43791badd51e16a41b99ecf6ac3204fa11b5c3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Nov 2022 19:24:22 +0100 Subject: [PATCH 72/99] Feature: [saved export] Edit and delete saved exports --- .../Controller/ExportController.php | 6 +- .../Controller/SavedExportController.php | 97 ++++++++++++++++++- .../views/SavedExport/delete.html.twig | 25 +++++ .../views/SavedExport/edit.html.twig | 21 ++++ .../views/SavedExport/index.html.twig | 12 ++- .../Authorization/SavedExportVoter.php | 15 ++- .../translations/messages.fr.yml | 6 ++ 7 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Resources/views/SavedExport/delete.html.twig create mode 100644 src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 293a3c778..84bf80c6b 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -170,7 +170,11 @@ class ExportController extends AbstractController return $this->redirectToRoute( 'chill_main_export_download', - ['alias' => $savedExport->getExportAlias(), 'key' => $key, 'prevent_save' => true] + [ + 'alias' => $savedExport->getExportAlias(), + 'key' => $key, 'prevent_save' => true, + 'returnPath' => $this->generateUrl('chill_main_export_saved_list_my'), + ] ); } diff --git a/src/Bundle/ChillMainBundle/Controller/SavedExportController.php b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php index 051fa5231..197fe253d 100644 --- a/src/Bundle/ChillMainBundle/Controller/SavedExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php @@ -16,38 +16,132 @@ use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\GroupedExportInterface; +use Chill\MainBundle\Form\SavedExportType; use Chill\MainBundle\Repository\SavedExportRepositoryInterface; +use Chill\MainBundle\Security\Authorization\SavedExportVoter; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Templating\EngineInterface; use Symfony\Contracts\Translation\TranslatorInterface; +use function count; class SavedExportController { + private EntityManagerInterface $entityManager; + private ExportManager $exportManager; + private FormFactoryInterface $formFactory; + private SavedExportRepositoryInterface $savedExportRepository; private Security $security; + private SessionInterface $session; + private EngineInterface $templating; private TranslatorInterface $translator; + private UrlGeneratorInterface $urlGenerator; + public function __construct( EngineInterface $templating, + EntityManagerInterface $entityManager, ExportManager $exportManager, + FormFactoryInterface $formBuilder, SavedExportRepositoryInterface $savedExportRepository, Security $security, - TranslatorInterface $translator + SessionInterface $session, + TranslatorInterface $translator, + UrlGeneratorInterface $urlGenerator ) { $this->exportManager = $exportManager; + $this->entityManager = $entityManager; + $this->formFactory = $formBuilder; $this->savedExportRepository = $savedExportRepository; $this->security = $security; + $this->session = $session; $this->templating = $templating; $this->translator = $translator; + $this->urlGenerator = $urlGenerator; + } + + /** + * @Route("/{_locale}/exports/saved/{id}/delete", name="chill_main_export_saved_delete") + */ + public function delete(SavedExport $savedExport, Request $request): Response + { + if (!$this->security->isGranted(SavedExportVoter::DELETE, $savedExport)) { + throw new AccessDeniedHttpException(); + } + + $form = $this->formFactory->create(); + $form->add('submit', SubmitType::class, ['label' => 'Delete']); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->remove($savedExport); + $this->entityManager->flush(); + + $this->session->getFlashBag()->add('success', $this->translator->trans('saved_export.Export is deleted')); + + return new RedirectResponse( + $this->urlGenerator->generate('chill_main_export_saved_list_my') + ); + } + + return new Response( + $this->templating->render( + '@ChillMain/SavedExport/delete.html.twig', + [ + 'saved_export' => $savedExport, + 'delete_form' => $form->createView(), + ] + ) + ); + } + + /** + * @Route("/{_locale}/exports/saved/{id}/edit", name="chill_main_export_saved_edit") + */ + public function edit(SavedExport $savedExport, Request $request): Response + { + if (!$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) { + throw new AccessDeniedHttpException(); + } + + $form = $this->formFactory->create(SavedExportType::class, $savedExport); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->flush(); + + $this->session->getFlashBag()->add('success', $this->translator->trans('saved_export.Saved export is saved!')); + + return new RedirectResponse( + $this->urlGenerator->generate('chill_main_export_saved_list_my') + ); + } + + return new Response( + $this->templating->render( + '@ChillMain/SavedExport/edit.html.twig', + [ + 'form' => $form->createView(), + ] + ) + ); } /** @@ -83,6 +177,7 @@ class SavedExportController '@ChillMain/SavedExport/index.html.twig', [ 'grouped_exports' => $exportsGrouped, + 'total' => count($exports), ] ) ); diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/delete.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/delete.html.twig new file mode 100644 index 000000000..5d90699df --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/delete.html.twig @@ -0,0 +1,25 @@ +{% extends '@ChillMain/layout.html.twig' %} + +{% block title 'saved_export.Delete saved ?'|trans %} + +{% block display_content %} +
+

{{ saved_export.title }}

+

{{ saved_export.description|chill_markdown_to_html }}

+ +
+{% endblock %} + +{% block content %} +
+ {{ include('@ChillMain/Util/confirmation_template.html.twig', + { + 'title' : 'saved_export.Delete saved ?'|trans, + 'confirm_question' : 'saved_export.Are you sure you want to delete this saved ?'|trans, + 'display_content' : block('display_content'), + 'cancel_route' : 'chill_main_export_saved_list_my', + 'cancel_parameters' : {}, + 'form' : delete_form + } ) }} +
+{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig new file mode 100644 index 000000000..937d42201 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig @@ -0,0 +1,21 @@ +{% extends "@ChillMain/layout.html.twig" %} + +{% block title %}{{ 'saved_export.Edit'|trans }}{% endblock %} + +{% block content %} +

{{ block('title') }}

+ + {{ form_start(form) }} + {{ form_row(form.title) }} + {{ form_row(form.description) }} + + + {{ form_end(form) }} +{% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index 5cd697bb4..bfe377f6c 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -8,6 +8,10 @@
+ {% if total == 0 %} +

{{ 'saved_export.Any saved export'|trans }}

+ {% endif %} + {% for group, saveds in grouped_exports %} {% if group != '_' %}

{{ group }}

@@ -21,8 +25,8 @@
    -
  • -
  • +
  • +
@@ -47,8 +51,8 @@
    -
  • -
  • +
  • +
diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php index bc74e2d45..667bced46 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/SavedExportVoter.php @@ -15,20 +15,33 @@ use Chill\MainBundle\Entity\SavedExport; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; use UnexpectedValueException; +use function in_array; class SavedExportVoter extends Voter { + public const DELETE = 'CHLL_MAIN_EXPORT_SAVED_DELETE'; + + public const EDIT = 'CHLL_MAIN_EXPORT_SAVED_EDIT'; + public const GENERATE = 'CHLL_MAIN_EXPORT_SAVED_GENERATE'; + private const ALL = [ + self::DELETE, + self::EDIT, + self::GENERATE, + ]; + protected function supports($attribute, $subject): bool { - return $subject instanceof SavedExport && self::GENERATE === $attribute; + return $subject instanceof SavedExport && in_array($attribute, self::ALL, true); } protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { /** @var SavedExport $subject */ switch ($attribute) { + case self::DELETE: + case self::EDIT: case self::GENERATE: return $subject->getUser() === $token->getUser(); diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 498f185b6..1100d8ee3 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -558,5 +558,11 @@ rolling_date: fixed_date_date: Date fixe saved_export: + Any saved export: Aucun rapport enregistré New: Nouveau rapport enregistré + Edit: Modifier un rapport enregistré + Delete saved ?: Supprimer un rapport enregistré ? + Are you sure you want to delete this saved ?: Êtes-vous sûr·e de vouloir supprimer ce rapport ? My saved exports: Mes rapports enregistrés + Export is deleted: Le rapport est supprimé + Saved export is saved!: Le rapport est enregistré \ No newline at end of file From be38251a13d0a336f2eedb04c88877141fa5b1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Nov 2022 19:59:43 +0100 Subject: [PATCH 73/99] Feature: [saved export] Switch between list of export and saved export thanks to nav at the list's top --- .../Resources/views/Export/_navbar.html.twig | 12 ++++ .../Resources/views/Export/layout.html.twig | 42 ++++++++----- .../views/SavedExport/index.html.twig | 59 ++++++++++++------- .../translations/messages.fr.yml | 3 +- 4 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Resources/views/Export/_navbar.html.twig diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/_navbar.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/_navbar.html.twig new file mode 100644 index 000000000..a7d7216b4 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/_navbar.html.twig @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig index 9cf53993d..5ce433535 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig @@ -22,9 +22,11 @@ {% block content %} + + {{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'common'}) }} +
-

{{ 'Exports list'|trans }}

- +
{% for group, exports in grouped_exports %}{% if group != '_' %} @@ -32,13 +34,17 @@
{% for export_alias, export in exports %}
-

{{ export.title|trans }}

-

{{ export.description|trans }}

-

- - {{ 'Create an export'|trans }} - -

+
+
+

{{ export.title|trans }}

+

{{ export.description|trans }}

+

+ + {{ 'Create an export'|trans }} + +

+
+
{% endfor %}
@@ -52,13 +58,17 @@ {% for export_alias,export in grouped_exports['_'] %}
-

{{ export.title|trans }}

-

{{ export.description|trans }}

-

- - {{ 'Create an export'|trans }} - -

+
+
+

{{ export.title|trans }}

+

{{ export.description|trans }}

+

+ + {{ 'Create an export'|trans }} + +

+
+
{% endfor %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index bfe377f6c..17792ecd2 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -4,7 +4,8 @@ {% block content %}
-

{{ block('title') }}

+ + {{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }}
@@ -18,17 +19,25 @@
{% for s in saveds %}
-

{{ s.saved.title }}

-

{{ s.export.title|trans }}

-
- {{ s.saved.description|chill_markdown_to_html }} -
+
+
+

{{ s.saved.title }}

+

{{ s.export.title|trans }}

-
    -
  • -
  • -
  • -
+
+ {{ s.saved.description|chill_markdown_to_html }} +
+ +
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
+ +
    +
  • +
  • +
  • +
+ +
+
{% endfor %}
@@ -44,17 +53,25 @@ {% for s in saveds %}
-

{{ s.saved.title }}

-

{{ s.export.title|trans }}

-
- {{ s.saved.description|chill_markdown_to_html }} -
+
+
+

{{ s.saved.title }}

+

{{ s.export.title|trans }}

-
    -
  • -
  • -
  • -
+
+ {{ s.saved.description|chill_markdown_to_html }} +
+ +
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
+ +
    +
  • +
  • +
  • +
+ +
+
{% endfor %} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 1100d8ee3..58b3e976e 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -565,4 +565,5 @@ saved_export: Are you sure you want to delete this saved ?: Êtes-vous sûr·e de vouloir supprimer ce rapport ? My saved exports: Mes rapports enregistrés Export is deleted: Le rapport est supprimé - Saved export is saved!: Le rapport est enregistré \ No newline at end of file + Saved export is saved!: Le rapport est enregistré + Created on %date%: Créé le %date% \ No newline at end of file From c22135f101e7683d8581f8ed076572591665ac8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 9 Nov 2022 14:50:22 +0100 Subject: [PATCH 74/99] Feature: [export] apply all filters valid for person on accompanying course --- .../Export/Export/CountAccompanyingCourse.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index d07ee3639..8988f4278 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -15,7 +15,6 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; @@ -100,11 +99,13 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface $qb ->andWhere('acp.step != :count_acp_step') + ->leftJoin('acp.participations', 'acppart') + ->leftJoin('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -125,6 +126,7 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface { return [ Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } From c1df8084a63fd7c83bd531950def97f5f5bebefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 9 Nov 2022 15:48:20 +0100 Subject: [PATCH 75/99] DX: Add DQL function LEAST and GREATEST --- .../ChillMainExtension.php | 4 ++ .../ChillMainBundle/Doctrine/DQL/Greatest.php | 57 +++++++++++++++++++ .../ChillMainBundle/Doctrine/DQL/Least.php | 57 +++++++++++++++++++ .../Tests/Doctrine/DQL/GreatestTest.php | 48 ++++++++++++++++ .../Tests/Doctrine/DQL/LeastTest.php | 48 ++++++++++++++++ 5 files changed, 214 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php create mode 100644 src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 7c63263ba..db54150ca 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -25,10 +25,12 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; use Chill\MainBundle\Doctrine\DQL\Age; use Chill\MainBundle\Doctrine\DQL\Extract; use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey; +use Chill\MainBundle\Doctrine\DQL\Greatest; use Chill\MainBundle\Doctrine\DQL\JsonAggregate; use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength; use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray; use Chill\MainBundle\Doctrine\DQL\JsonExtract; +use Chill\MainBundle\Doctrine\DQL\Least; use Chill\MainBundle\Doctrine\DQL\OverlapsI; use Chill\MainBundle\Doctrine\DQL\Replace; use Chill\MainBundle\Doctrine\DQL\Similarity; @@ -246,6 +248,8 @@ class ChillMainExtension extends Extension implements 'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class, 'ST_X' => STX::class, 'ST_Y' => STY::class, + 'GREATEST' => Greatest::class, + 'LEAST' => LEAST::class, ], 'datetime_functions' => [ 'EXTRACT' => Extract::class, diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php new file mode 100644 index 000000000..b9ca9c4b6 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Greatest.php @@ -0,0 +1,57 @@ +dispatch($sqlWalker); + }, $this->exprs)) . ')'; + } + + public function parse(Parser $parser) + { + $this->exprs = []; + + $lexer = $parser->getLexer(); + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->exprs[] = $parser->ArithmeticPrimary(); + + while (Lexer::T_COMMA === $lexer->lookahead['type']) { + $parser->match(Lexer::T_COMMA); + $this->exprs[] = $parser->ArithmeticPrimary(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php new file mode 100644 index 000000000..0c8a1b17d --- /dev/null +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Least.php @@ -0,0 +1,57 @@ +dispatch($sqlWalker); + }, $this->exprs)) . ')'; + } + + public function parse(Parser $parser) + { + $this->exprs = []; + + $lexer = $parser->getLexer(); + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->exprs[] = $parser->ArithmeticPrimary(); + + while (Lexer::T_COMMA === $lexer->lookahead['type']) { + $parser->match(Lexer::T_COMMA); + $this->exprs[] = $parser->ArithmeticPrimary(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php new file mode 100644 index 000000000..c11061287 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/GreatestTest.php @@ -0,0 +1,48 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function testGreatestInDQL() + { + $dql = 'SELECT GREATEST(a.validFrom, a.validTo, :now) AS g FROM ' . Address::class . ' a WHERE a.validTo < :now and a.validFrom < :now'; + + $actual = $this->entityManager + ->createQuery($dql) + ->setParameter('now', $now = new DateTimeImmutable('now'), Types::DATE_IMMUTABLE) + ->setMaxResults(3) + ->getResult(); + + $this->assertIsArray($actual); + $this->assertEquals($now->format('Y-m-d'), $actual[0]['g']); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php new file mode 100644 index 000000000..1e5be8e24 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Doctrine/DQL/LeastTest.php @@ -0,0 +1,48 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + public function testGreatestInDQL() + { + $dql = 'SELECT LEAST(a.validFrom, a.validTo, :now) AS g FROM ' . Address::class . ' a WHERE a.validTo < :now and a.validFrom < :now'; + + $actual = $this->entityManager + ->createQuery($dql) + ->setParameter('now', $now = new DateTimeImmutable('now'), Types::DATE_IMMUTABLE) + ->setMaxResults(3) + ->getResult(); + + $this->assertIsArray($actual); + $this->assertNotEquals($now->format('Y-m-d'), $actual[0]['g']); + } +} From 826a975fbe0944566f89aa88a4bddabd570de980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 9 Nov 2022 16:20:24 +0100 Subject: [PATCH 76/99] Features: apply all the filters and aggregators concerning person on accompanying courses --- .../Export/Export/CountAccompanyingCourse.php | 2 +- .../Export/StatAccompanyingCourseDuration.php | 62 +++++++++++++------ .../translations/messages.fr.yml | 10 ++- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index 8988f4278..a9f794888 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -101,7 +101,7 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface ->andWhere('acp.step != :count_acp_step') ->leftJoin('acp.participations', 'acppart') ->leftJoin('acppart.person', 'person') - ->andWhere('acppart.startDate != acppart.endDate') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person diff --git a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php index a0e68beea..c124f0227 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php @@ -16,7 +16,6 @@ use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; @@ -53,7 +52,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getDescription(): string { - return 'Create an average of accompanying courses duration according to various filters'; + return 'Create an average of accompanying courses duration of each person participation to accompanying course, according to filters on persons, accompanying course'; } public function getGroup(): string @@ -63,21 +62,37 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getLabels($key, array $values, $data) { - if ('export_result' !== $key) { - throw new LogicException("the key {$key} is not used by this export"); - } + return static function ($value) use ($key) { + if ('_header' === $value) { + switch ($key) { + case 'avg_export_result': + return 'export.export.acp_stats.avg_duration'; - $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); + case 'count_acppart_export_result': + return 'export.export.acp_stats.count_participations'; - return static function ($value) use ($labels) { - return $labels[$value]; + case 'count_acp_export_result': + return 'export.export.acp_stats.count_acps'; + + case 'count_pers_export_result': + return 'export.export.acp_stats.count_persons'; + + default: + throw new LogicException('key not supported: ' . $key); + } + } + + if (null === $value) { + return ''; + } + + return $value; }; } public function getQueryKeys($data): array { - return ['export_result']; + return ['avg_export_result', 'count_acp_export_result', 'count_acppart_export_result', 'count_pers_export_result']; } public function getResult($query, $data) @@ -87,7 +102,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn public function getTitle(): string { - return 'Accompanying courses duration'; + return 'Accompanying courses participation duration and number of participations'; } public function getType(): string @@ -104,22 +119,28 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn $qb = $this->repository->createQueryBuilder('acp'); $qb + ->select('AVG( + LEAST(acppart.endDate, COALESCE(acp.closingDate, :force_closingDate)) + - GREATEST(acppart.startDate, COALESCE(acp.openingDate, :force_closingDate)) + ) AS avg_export_result') + ->addSelect('COUNT(DISTINCT acppart.id) AS count_acppart_export_result') + ->addSelect('COUNT(DISTINCT person.id) AS count_pers_export_result') + ->addSelect('COUNT(DISTINCT acp.id) AS count_acp_export_result') + ->setParameter('force_closingDate', $data['closingdate']) + ->leftJoin('acp.participations', 'acppart') + ->leftJoin('acppart.person', 'person') + ->andWhere('acp.step != :count_acp_step') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) + ->setParameter('count_acp_step', AccompanyingPeriod::STEP_DRAFT) ->setParameter('authorized_centers', $centers); - $qb - ->select('AVG( - COALESCE(acp.closingDate, :force_closingDate) - acp.openingDate - ) AS export_result') - ->setParameter('force_closingDate', $data['closingdate']); - return $qb; } @@ -132,6 +153,7 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn { return [ Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index bdedea895..022ac5654 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -359,8 +359,8 @@ Count people participating in an accompanying course by various parameters.: Com Exports of accompanying courses: Exports des parcours d'accompagnement Count accompanying courses: Nombre de parcours Count accompanying courses by various parameters: Compte le nombre de parcours en fonction de différents filtres. -Accompanying courses duration: Durée moyenne des parcours -Create an average of accompanying courses duration according to various filters: Moyenne de la durée des parcours en jours, selon différents filtres. +Accompanying courses participation duration and number of participations: Durée moyenne et nombre des participation des usagers aux parcours +Create an average of accompanying courses duration of each person participation to accompanying course, according to filters on persons, accompanying course: Crée un rapport qui comptabilise la moyenne de la durée de participation de chaque usager concerné aux parcours, avec différents filtres, notamment sur les usagers concernés. Closingdate to apply: Date de fin à prendre en compte lorsque le parcours n'est pas clotûré Exports of social work actions: Exports des actions d'accompagnement @@ -989,6 +989,12 @@ notification: Notify any: Notifier d'autres utilisateurs export: + export: + acp_stats: + avg_duration: Moyenne de la durée de participation de chaque usager concerné + count_participations: Nombre de participations distinctes + count_persons: Nombre d'usagers concernés distincts + count_acps: Nombre de parcours distincts aggregator: course: by_referrer: From a942a24596bf4881ac7a70b3baa2b8c06a662805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 9 Nov 2022 20:46:15 +0100 Subject: [PATCH 77/99] Fixes: [export] fixes filters by household composition, and apply them on persons directly --- .../ByHouseholdCompositionAggregator.php | 36 ++---- .../Export/Export/CountPerson.php | 2 +- .../ByHouseholdCompositionFilter.php | 110 ++++++++++++++++++ .../services/exports_accompanying_course.yaml | 4 - .../config/services/exports_person.yaml | 11 ++ .../translations/messages.fr.yml | 15 ++- 6 files changed, 145 insertions(+), 33 deletions(-) rename src/Bundle/ChillPersonBundle/Export/Aggregator/{AccompanyingCourseAggregators => PersonAggregators}/ByHouseholdCompositionAggregator.php (75%) create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php similarity index 75% rename from src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php rename to src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php index f299762e6..7a1aaaa49 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php @@ -9,20 +9,18 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; +namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\HouseholdComposition; -use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface; use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class ByHouseholdCompositionAggregator implements AggregatorInterface { @@ -47,30 +45,20 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface { $p = self::PREFIX; - if (!in_array('acppart', $qb->getAllAliases(), true)) { - $qb->leftJoin('acp.participations', 'acppart'); - } - $qb ->leftJoin( - HouseholdMember::class, - "{$p}_hm", - Join::WITH, - $qb->expr()->orX( - $qb->expr()->isNull("{$p}_hm"), - $qb->expr()->andX( - $qb->expr()->lte("{$p}_hm.startDate", ":{$p}_date"), - $qb->expr()->orX( - $qb->expr()->isNull("{$p}_hm.endDate"), - $qb->expr()->gt("{$p}_hm.endDate", ":{$p}_date") - ) - ) - ) + 'person.householdParticipations', + "{$p}_hm" ) ->leftJoin( HouseholdComposition::class, "{$p}_compo", Join::WITH, + $qb->expr()->eq("{$p}_hm.household", "{$p}_compo.household"), + ) + ->andWhere("{$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)") + ->andWhere("{$p}_hm.shareHousehold = 'TRUE'") + ->andWhere( $qb->expr()->orX( $qb->expr()->isNull("{$p}_compo"), $qb->expr()->andX( @@ -89,13 +77,13 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface public function applyOn() { - return Declarations::ACP_TYPE; + return Declarations::PERSON_TYPE; } public function buildForm(FormBuilderInterface $builder) { $builder->add('date_calc', ChillDateType::class, [ - 'label' => 'export.aggregator.course.by_household_composition.Calc date', + 'label' => 'export.aggregator.person.by_household_composition.Calc date', 'input_format' => 'datetime_immutable', 'data' => new DateTimeImmutable('now'), ]); @@ -105,7 +93,7 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface { return function ($value) { if ('_header' === $value) { - return 'export.aggregator.course.by_household_composition.Household composition'; + return 'export.aggregator.person.by_household_composition.Household composition'; } if (null === $value) { @@ -127,6 +115,6 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface public function getTitle() { - return 'export.aggregator.course.by_household_composition.Group course by household composition'; + return 'export.aggregator.person.by_household_composition.Group course by household composition'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index 98708149a..07a307563 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -100,7 +100,7 @@ class CountPerson implements ExportInterface, GroupedExportInterface $qb = $this->personRepository->createQueryBuilder('person'); - $qb->select('COUNT(person.id) AS export_result') + $qb->select('COUNT(DISTINCT person.id) AS export_result') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)' diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php new file mode 100644 index 000000000..9b59549f1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php @@ -0,0 +1,110 @@ +householdCompositionTypeRepository = $householdCompositionTypeRepository; + $this->rollingDateConverter = $rollingDateConverter; + $this->translatableStringHelper = $translatableStringHelper; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = 'person_by_household_compo_filter'; + + $qb + ->andWhere( + $qb->expr()->exists( + 'SELECT 1 FROM ' . HouseholdMember::class . " {$p}_hm " . + 'JOIN ' . HouseholdComposition::class . " {$p}_compo WITH {$p}_hm.household = {$p}_compo.household " . + "WHERE {$p}_hm.person = person AND {$p}_hm.shareHousehold = 'TRUE' " . + "AND ({$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)) " . + "AND ({$p}_compo.startDate <= :{$p}_date AND ({$p}_compo.endDate IS NULL OR {$p}_compo.endDate > :{$p}_date)) " . + "AND {$p}_compo.householdCompositionType IN (:{$p}_accepted)" + ) + ) + ->setParameter("{$p}_accepted", $data['compositions']) + ->setParameter("{$p}_date", $this->rollingDateConverter->convert($data['calc_date']), Types::DATE_IMMUTABLE); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('compositions', EntityType::class, [ + 'class' => HouseholdCompositionType::class, + 'choices' => $this->householdCompositionTypeRepository->findAllActive(), + 'choice_label' => fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()), + 'label' => 'export.filter.person.by_composition.Accepted compositions', + 'multiple' => true, + 'expanded' => true, + ]) + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.filter.person.by_composition.Date calc', + 'data' => new RollingDate(RollingDate::T_TODAY), + ]); + } + + public function describeAction($data, $format = 'string') + { + $compos = array_map( + fn (HouseholdCompositionType $compositionType) => $this->translatableStringHelper->localize($compositionType->getLabel()), + $data['compositions']->toArray() + ); + + return ['export.filter.person.by_composition.Filtered by composition at %date%: only %compositions%', [ + '%compositions%' => implode(', ', $compos), + '%date%' => $this->rollingDateConverter->convert($data['calc_date'])->format('d-m-Y'), + ]]; + } + + public function getTitle() + { + return 'export.filter.person.by_composition.Filter by household composition'; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml index 71eecf4ff..6d0e160fd 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_course.yaml @@ -214,10 +214,6 @@ services: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_ref_scope_aggregator } - Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByHouseholdCompositionAggregator: - tags: - - { name: chill.export_aggregator, alias: accompanyingcourse_by_household_compo_aggregator } - Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators\ByActionNumberAggregator: tags: - { name: chill.export_aggregator, alias: accompanyingcourse_by_action_number_aggregator } diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index b2b182c5b..05ae4b7b2 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -1,4 +1,7 @@ services: + _defaults: + autoconfigure: true + autowire: true ## Indicators chill.person.export.count_person: @@ -107,6 +110,10 @@ services: tags: - { name: chill.export_filter, alias: person_geog_filter } + Chill\PersonBundle\Export\Filter\PersonFilters\ByHouseholdCompositionFilter: + tags: + - { name: chill.export_filter, alias: person_by_household_composition_filter } + ## Aggregators chill.person.export.aggregator_nationality: class: Chill\PersonBundle\Export\Aggregator\PersonAggregators\NationalityAggregator @@ -156,3 +163,7 @@ services: tags: - { name: chill.export_aggregator, alias: person_geog_aggregator } + Chill\PersonBundle\Export\Aggregator\PersonAggregators\ByHouseholdCompositionAggregator: + tags: + - { name: chill.export_aggregator, alias: person_household_compo_aggregator } + diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 022ac5654..41919fe4d 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -996,6 +996,11 @@ export: count_persons: Nombre d'usagers concernés distincts count_acps: Nombre de parcours distincts aggregator: + person: + by_household_composition: + Household composition: Composition du ménage + Group course by household composition: Grouper les personnes par composition familiale + Calc date: Date de calcul de la composition du ménage course: by_referrer: Computation date for referrer: Date à laquelle le référent était actif @@ -1008,10 +1013,6 @@ export: week: Durée du parcours en semaines month: Durée du parcours en mois Precision: Unité de la durée - by_household_composition: - Household composition: Composition du ménage - Group course by household composition: Grouper les parcours par composition familiale des ménages des usagers concernés - Calc date: Date de calcul de la composition du ménage by_number_of_action: Number of actions: Nombre d'actions by_creator_job: @@ -1038,6 +1039,12 @@ export: Max date: Date d'échéance filter: + person: + by_composition: + Filter by household composition: Filtrer les personnes par composition du ménage + Accepted compositions: Composition de ménages + Date calc: Date de calcul + 'Filtered by composition at %date%: only %compositions%': 'Filtré par composition du ménage, le %date%, seulement %compositions%' course: by_user_scope: Computation date for referrer: Date à laquelle le référent était actif From a7c44830d2466a440bdf51ff9e6a06ee892e8025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Nov 2022 15:11:45 +0100 Subject: [PATCH 78/99] Features: [export] Filter "persons who do not have a household composition" --- .../WithoutHouseholdComposition.php | 84 +++++++++++++++++++ .../config/services/exports_person.yaml | 4 + .../translations/messages.fr.yml | 5 ++ 3 files changed, 93 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php new file mode 100644 index 000000000..c4644fc11 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php @@ -0,0 +1,84 @@ +rollingDateConverter = $rollingDateConverter; + } + + public function addRole(): ?string + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $p = 'person_by_household_no_compo_filter'; + + $qb + ->andWhere( + $qb->expr()->not( + $qb->expr()->exists( + 'SELECT 1 FROM ' . HouseholdMember::class . " {$p}_hm " . + 'JOIN ' . HouseholdComposition::class . " {$p}_compo WITH {$p}_hm.household = {$p}_compo.household " . + "WHERE {$p}_hm.person = person AND {$p}_hm.shareHousehold = 'TRUE' " . + "AND ({$p}_hm.startDate <= :{$p}_date AND ({$p}_hm.endDate IS NULL OR {$p}_hm.endDate > :{$p}_date)) " . + "AND ({$p}_compo.startDate <= :{$p}_date AND ({$p}_compo.endDate IS NULL OR {$p}_compo.endDate > :{$p}_date)) " + ) + ) + ) + ->setParameter("{$p}_date", $this->rollingDateConverter->convert($data['calc_date']), Types::DATE_IMMUTABLE); + } + + public function applyOn() + { + return Declarations::PERSON_TYPE; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('calc_date', PickRollingDateType::class, [ + 'label' => 'export.filter.person.by_no_composition.Date calc', + 'data' => new RollingDate(RollingDate::T_TODAY), + ]); + } + + public function describeAction($data, $format = 'string') + { + return ['export.filter.person.by_no_composition.Persons filtered by no composition at %date%', [ + '%date%' => $this->rollingDateConverter->convert($data['calc_date'])->format('d-m-Y'), + ]]; + } + + public function getTitle() + { + return 'export.filter.person.by_no_composition.Filter persons without household composition'; + } +} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml index 05ae4b7b2..a8563e5ca 100644 --- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml @@ -114,6 +114,10 @@ services: tags: - { name: chill.export_filter, alias: person_by_household_composition_filter } + Chill\PersonBundle\Export\Filter\PersonFilters\WithoutHouseholdComposition: + tags: + - { name: chill.export_filter, alias: person_without_household_composition_filter } + ## Aggregators chill.person.export.aggregator_nationality: class: Chill\PersonBundle\Export\Aggregator\PersonAggregators\NationalityAggregator diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 41919fe4d..6ca594dc1 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1045,6 +1045,11 @@ export: Accepted compositions: Composition de ménages Date calc: Date de calcul 'Filtered by composition at %date%: only %compositions%': 'Filtré par composition du ménage, le %date%, seulement %compositions%' + by_no_composition: + Filter persons without household composition: Filtrer les personnes sans composition de ménage (ni ménage) + Persons filtered by no composition at %date%: Uniquement les personnes sans composition de ménage à la date du %date% + Date calc: Date de calcul + course: by_user_scope: Computation date for referrer: Date à laquelle le référent était actif From 8e44f20535990beb34e178dfcde7ffb9cf70393f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Nov 2022 15:21:56 +0100 Subject: [PATCH 79/99] Features: [export] Remove old unnecessary filters for person with accompanying period Those filters applyed on persons and allowed to select person which has a new, closing, or active accompanying period. But this is deprecated: there are now a dedicated Export for that ( CountPersonWithAccompanyingCourse) --- .../ChillPersonExtension.php | 12 ++- .../AccompanyingPeriodClosingFilter.php | 78 ---------------- .../AccompanyingPeriodFilter.php | 87 ------------------ .../AccompanyingPeriodOpeningFilter.php | 78 ---------------- .../AccompanyingPeriodClosingFilterTest.php | 90 ------------------- .../AccompanyingPeriodFilterTest.php | 90 ------------------- .../AccompanyingPeriodOpeningFilterTest.php | 90 ------------------- .../services/exports_accompanying_period.yaml | 16 ---- 8 files changed, 5 insertions(+), 536 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php delete mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php delete mode 100644 src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php delete mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php delete mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php delete mode 100644 src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php delete mode 100644 src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 932f5b9f9..d60e15e41 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -97,11 +97,11 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $loader->load('services/exports_person.yaml'); if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') { - $loader->load('services/exports_accompanying_period.yaml'); + $loader->load('services/exports_accompanying_course.yaml'); + $loader->load('services/exports_social_actions.yaml'); + $loader->load('services/exports_evaluation.yaml'); } - $loader->load('services/exports_accompanying_course.yaml'); - $loader->load('services/exports_social_actions.yaml'); - $loader->load('services/exports_evaluation.yaml'); + $loader->load('services/exports_household.yaml'); } @@ -944,10 +944,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac /** * Add a widget "add a person" on the homepage, automatically. - * - * @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container */ - protected function prependHomepageWidget(containerBuilder $container) + protected function prependHomepageWidget(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ 'widgets' => [ diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php deleted file mode 100644 index 8c6c132b7..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilter.php +++ /dev/null @@ -1,78 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX( - $qb->expr()->lte('acp.closingDate', ':date_to'), - $qb->expr()->gte('acp.closingDate', ':date_from') - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period closed after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period closed before this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' closed between the %date_from% and %date_to%', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: closed between two dates'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php deleted file mode 100644 index 05cf7fd1e..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodFilter.php +++ /dev/null @@ -1,87 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX(); - - $clause->add( - $qb->expr()->lte('acp.openingDate', ':date_to') - ); - $clause->add( - $qb->expr()->orX( - $qb->expr()->gte('acp.closingDate', ':date_from'), - $qb->expr()->isNull('acp.closingDate') - ) - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period ending before this date, or ' - . 'still opened at this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' opened after the %date_from% and closed before the %date_to% (or still opened ' - . 'at the %date_to%)', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: active period'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php deleted file mode 100644 index b6d895233..000000000 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilter.php +++ /dev/null @@ -1,78 +0,0 @@ -addJoinAccompanyingPeriod($qb); - - $clause = $qb->expr()->andX( - $qb->expr()->lte('acp.openingDate', ':date_to'), - $qb->expr()->gte('acp.openingDate', ':date_from') - ); - - $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); - } - - public function applyOn(): string - { - return Declarations::PERSON_TYPE; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('date_from', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened after this date', - 'data' => new DateTime('-1 month'), - ]); - - $builder->add('date_to', ChillDateType::class, [ - 'label' => 'Having an accompanying period opened before this date', - 'data' => new DateTime(), - ]); - } - - public function describeAction($data, $format = 'string') - { - return [ - 'Filtered by accompanying period: persons having an accompanying period' - . ' opened between the %date_from% and %date_to%', - [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - ], - ]; - } - - public function getTitle(): string - { - return 'Filter by accompanying period: starting between two dates'; - } -} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php deleted file mode 100644 index 76c3b40b5..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodClosingFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period_closing'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData(): array - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders(): array - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php deleted file mode 100644 index 582d090e8..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData() - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders() - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php deleted file mode 100644 index 9262d0757..000000000 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/PersonFilters/AccompanyingPeriodOpeningFilterTest.php +++ /dev/null @@ -1,90 +0,0 @@ -filter = self::$container->get('chill.person.export.filter_accompanying_period_opening'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped('The current configuration does not use accompanying_periods'); - } - } - - public function getFilter() - { - return $this->filter; - } - - public function getFormData() - { - return [ - [ - 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), - ], - ]; - } - - public function getQueryBuilders() - { - if (null === self::$kernel) { - self::bootKernel(); - } - - $em = self::$container - ->get('doctrine.orm.entity_manager'); - - return [ - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person'), - $em->createQueryBuilder() - ->select('person.firstName') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('count(IDENTITY(p))') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.accompanyingPeriods', 'accompanying_period') - // add a dummy where clause - ->where('person.firstname IS NOT NULL'), - $em->createQueryBuilder() - ->select('activity.date AS date') - ->select('activity.attendee as attendee') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center'), - ]; - } -} diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml deleted file mode 100644 index 42ddd2181..000000000 --- a/src/Bundle/ChillPersonBundle/config/services/exports_accompanying_period.yaml +++ /dev/null @@ -1,16 +0,0 @@ -services: - - chill.person.export.filter_accompanying_period: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodFilter - tags: - - { name: chill.export_filter, alias: person_accc_period_filter } - - chill.person.export.filter_accompanying_period_opening: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodOpeningFilter - tags: - - { name: chill.export_filter, alias: person_acc_pe_op_filter } - - chill.person.export.filter_accompanying_period_closing: - class: Chill\PersonBundle\Export\Filter\PersonFilters\AccompanyingPeriodClosingFilter - tags: - - { name: chill.export_filter, alias: person_acc_pe_cl_filter } From 61f44396c5a238bf2ccab1e1a98967fb0759a222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Nov 2022 15:51:46 +0100 Subject: [PATCH 80/99] Features: [export] Apply person filters and aggreators on Count Social Works export --- .../Export/Export/CountSocialWorkActions.php | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php index 9333312fd..0aaf526cc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountSocialWorkActions.php @@ -15,12 +15,10 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use LogicException; @@ -28,12 +26,12 @@ use Symfony\Component\Form\FormBuilderInterface; class CountSocialWorkActions implements ExportInterface, GroupedExportInterface { - protected EntityRepository $repository; + protected EntityManagerInterface $em; public function __construct( EntityManagerInterface $em ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->em = $em; } public function buildForm(FormBuilderInterface $builder): void @@ -96,15 +94,18 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository->createQueryBuilder('acp') - ->join('acp.works', 'acpw'); + $qb = $this->em->createQueryBuilder(); $qb + ->from(AccompanyingPeriod\AccompanyingPeriodWork::class, 'acpw') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acp.participations', 'acppart') + ->join('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -125,6 +126,7 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface return [ Declarations::SOCIAL_WORK_ACTION_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } From 91e3588e76b2d54d388c9b1352bbd19aa779b954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Nov 2022 21:17:48 +0100 Subject: [PATCH 81/99] Features: [export] Show also SocialIssue in the By Social Action aggregator --- .../ActionTypeAggregator.php | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php index fbdac5d40..0a42fd928 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php @@ -14,8 +14,11 @@ namespace Chill\PersonBundle\Export\Aggregator\SocialWorkAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository; +use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; use Chill\PersonBundle\Templating\Entity\SocialActionRender; +use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -25,12 +28,20 @@ final class ActionTypeAggregator implements AggregatorInterface private SocialActionRepository $socialActionRepository; + private SocialIssueRender $socialIssueRender; + + private SocialIssueRepository $socialIssueRepository; + public function __construct( SocialActionRepository $socialActionRepository, - SocialActionRender $actionRender + SocialActionRender $actionRender, + SocialIssueRender $socialIssueRender, + SocialIssueRepository $socialIssueRepository ) { $this->socialActionRepository = $socialActionRepository; $this->actionRender = $actionRender; + $this->socialIssueRender = $socialIssueRender; + $this->socialIssueRepository = $socialIssueRepository; } public function addRole(): ?string @@ -44,8 +55,15 @@ final class ActionTypeAggregator implements AggregatorInterface $qb->leftJoin('acpw.socialAction', 'acpwsocialaction'); } - $qb->addSelect('acpwsocialaction.id as action_type_aggregator'); - $qb->addGroupBy('action_type_aggregator'); + if (!in_array('acpwsocialissue', $qb->getAllAliases(), true)) { + $qb->leftJoin('acpwsocialaction.issue', 'acpwsocialissue'); + } + + $qb + ->addSelect('acpwsocialissue.id as social_action_type_aggregator') + ->addSelect('acpwsocialaction.id as action_type_aggregator') + ->addGroupBy('action_type_aggregator') + ->addGroupBy('social_action_type_aggregator'); } public function applyOn() @@ -60,24 +78,41 @@ final class ActionTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data) { - return function ($value): string { - if ('_header' === $value) { - return 'Social Action Type'; - } + switch ($key) { + case 'action_type_aggregator': + return function ($value): string { + if ('_header' === $value) { + return 'Social Action Type'; + } - if (null === $value) { - return ''; - } + if (null === $value || null === $sa = $this->socialActionRepository->find($value)) { + return ''; + } - $sa = $this->socialActionRepository->find($value); + return $this->actionRender->renderString($sa, []); + }; - return $this->actionRender->renderString($sa, []); - }; + case 'social_action_type_aggregator': + return function ($value): string { + if ('_header' === $value) { + return 'Social Issue'; + } + + if (null === $value || null === $si = $this->socialIssueRepository->find($value)) { + return ''; + } + + return $this->socialIssueRender->renderString($si, []); + }; + + default: + throw new LogicException('this key is not supported: ' . $key); + } } public function getQueryKeys($data) { - return ['action_type_aggregator']; + return ['social_action_type_aggregator', 'action_type_aggregator']; } public function getTitle() From 400770123a639a6ae998b8eb1f9669f5ced60a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 10:46:13 +0100 Subject: [PATCH 82/99] Features: [export] Apply person filters and aggreators on Count Evaluation --- .../Export/Export/CountEvaluation.php | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php index e62752d13..578cc1452 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php @@ -15,25 +15,22 @@ use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use LogicException; use Symfony\Component\Form\FormBuilderInterface; -use function in_array; class CountEvaluation implements ExportInterface, GroupedExportInterface { - private EntityRepository $repository; + private EntityManagerInterface $entityManager; public function __construct( EntityManagerInterface $em ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->entityManager = $em; } public function buildForm(FormBuilderInterface $builder) @@ -96,22 +93,19 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository->createQueryBuilder('acp'); - - if (!in_array('acpw', $qb->getAllAliases(), true)) { - $qb->join('acp.works', 'acpw'); - } - - if (!in_array('workeval', $qb->getAllAliases(), true)) { - $qb->join('acpw.accompanyingPeriodWorkEvaluations', 'workeval'); - } + $qb = $this->entityManager->createQueryBuilder(); $qb + ->from(AccompanyingPeriod\AccompanyingPeriodWorkEvaluation::class, 'workeval') + ->join('workeval.accompanyingPeriodWork', 'acpw') + ->join('acpw.accompanyingPeriod', 'acp') + ->join('acp.participations', 'acppart') + ->join('acppart.person', 'person') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) @@ -133,6 +127,7 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface Declarations::EVAL_TYPE, Declarations::SOCIAL_WORK_ACTION_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } From a68422e0e826970f61aef157921305ccf1ba45be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 11:21:16 +0100 Subject: [PATCH 83/99] Features: [export] Apply person filters and aggreators on Count Household --- .../Export/Export/CountHousehold.php | 84 ++++++++++++------- .../translations/messages.fr.yml | 8 +- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php index 0c838beff..f1eaeb4cb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php @@ -14,31 +14,42 @@ namespace Chill\PersonBundle\Export\Export; use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\GroupedExportInterface; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; -use Chill\PersonBundle\Entity\Household\HouseholdMember; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; +use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Person\PersonCenterHistory; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Security\Authorization\HouseholdVoter; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; use LogicException; use Symfony\Component\Form\FormBuilderInterface; class CountHousehold implements ExportInterface, GroupedExportInterface { - private EntityRepository $repository; + private const TR_PREFIX = 'export.export.nb_household_with_course.'; + + private EntityManagerInterface $entityManager; + + private RollingDateConverterInterface $rollingDateConverter; public function __construct( - EntityManagerInterface $em + EntityManagerInterface $em, + RollingDateConverterInterface $rollingDateConverter ) { - $this->repository = $em->getRepository(AccompanyingPeriod::class); + $this->entityManager = $em; + $this->rollingDateConverter = $rollingDateConverter; } public function buildForm(FormBuilderInterface $builder) { - // TODO: Implement buildForm() method. + $builder + ->add('calc_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), + 'label' => self::TR_PREFIX . 'Date of calculation of household members', + 'required' => false, + ]); } public function getAllowedFormattersTypes(): array @@ -48,7 +59,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getDescription(): string { - return 'Count household by various parameters.'; + return self::TR_PREFIX . 'Count household with accompanying course by various parameters.'; } public function getGroup(): string @@ -58,21 +69,31 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getLabels($key, array $values, $data) { - if ('export_result' !== $key) { - throw new LogicException("the key {$key} is not used by this export"); - } + return static function ($value) use ($key) { + if ('_header' === $value) { + switch ($key) { + case 'household_export_result': + return self::TR_PREFIX . 'Count households'; - $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); + case 'acp_export_result': + return self::TR_PREFIX . 'Count accompanying periods'; - return static function ($value) use ($labels) { - return $labels[$value]; + default: + throw new LogicException('Key not supported: ' . $key); + } + } + + if (null === $value) { + return ''; + } + + return $value; }; } public function getQueryKeys($data): array { - return ['export_result']; + return ['household_export_result', 'acp_export_result']; } public function getResult($query, $data) @@ -82,7 +103,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface public function getTitle(): string { - return 'Count households'; + return self::TR_PREFIX . 'Count households with accompanying course'; } public function getType(): string @@ -96,25 +117,29 @@ class CountHousehold implements ExportInterface, GroupedExportInterface return $el['center']; }, $acl); - $qb = $this->repository - ->createQueryBuilder('acp') - ->join('acp.participations', 'acppart') - // little optimization: we remove joins and make a direct join between participations and household members - ->join(HouseholdMember::class, 'member', Query\Expr\Join::WITH, 'IDENTITY(acppart.person) = IDENTITY(member.person)') - ->join('member.household', 'household'); + $qb = $this->entityManager->createQueryBuilder(); $qb + ->from(Household::class, 'household') + ->join('household.members', 'hmember') + ->join('hmember.person', 'person') + ->join('person.accompanyingPeriodParticipations', 'acppart') + ->join('acppart.accompanyingPeriod', 'acp') + ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( - 'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part - JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person) - WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) + 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person + AND acl_count_person_history.center IN (:authorized_centers) ' ) ) - ->setParameter('authorized_centers', $centers); + ->andWhere('hmember.startDate <= :count_household_at_date AND (hmember.endDate IS NULL OR hmember.endDate > :count_household_at_date)') + ->setParameter('authorized_centers', $centers) + ->setParameter('count_household_at_date', $this->rollingDateConverter->convert($data['calc_date'])); - $qb->select('COUNT(DISTINCT household.id) AS export_result'); + $qb + ->select('COUNT(DISTINCT household.id) AS household_export_result') + ->addSelect('COUNT(DISTINCT acp.id) AS acp_export_result'); return $qb; } @@ -129,6 +154,7 @@ class CountHousehold implements ExportInterface, GroupedExportInterface return [ Declarations::HOUSEHOLD_TYPE, Declarations::ACP_TYPE, + Declarations::PERSON_TYPE, ]; } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 6ca594dc1..0b53bd7a5 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -373,8 +373,6 @@ Count evaluations: Nombre d'évaluations Count evaluation by various parameters.: Compte le nombre d'évaluations selon différents filtres. Exports of households: Exports des ménages -Count households: Nombre de ménages -Count household by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. ## persons filters Filter by person gender: Filtrer les personnes par genre @@ -995,6 +993,12 @@ export: count_participations: Nombre de participations distinctes count_persons: Nombre d'usagers concernés distincts count_acps: Nombre de parcours distincts + nb_household_with_course: + Count households with accompanying course: Nombre de ménages impliqués dans un parcours + Count households: Nombre de ménages + Count accompanying periods: Nombre de parcours + Count household with accompanying course by various parameters.: Compte le nombre de ménages impliqués dans un parcours selon différents filtres. + Date of calculation of household members: Date à laquelle les membres du ménages sont comptabilisés aggregator: person: by_household_composition: From d3ba11f52111102c7c6d6cbf4a15c2cb91a8c7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 12:07:52 +0100 Subject: [PATCH 84/99] Feature: Store location of each address contained in geographical units in a materialized view --- src/Bundle/ChillMainBundle/Entity/Address.php | 31 +++++++++++++- .../migrations/Version20221114105345.php | 42 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20221114105345.php diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php index 2ddb48fda..1540fec54 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -15,6 +15,8 @@ use Chill\MainBundle\Doctrine\Model\Point; use Chill\ThirdPartyBundle\Entity\ThirdParty; use DateTime; use DateTimeInterface; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Context\ExecutionContextInterface; @@ -97,6 +99,23 @@ class Address */ private $floor; + /** + * List of geographical units and addresses. + * + * This list is computed by a materialized view. It won't be populated until a refresh is done + * on the materialized view. + * + * @var Collection|GeographicalUnit[] + * @readonly + * @ORM\ManyToMany(targetEntity=GeographicalUnit::class) + * @ORM\JoinTable( + * name="view_chill_main_address_geographical_unit", + * joinColumns={@ORM\JoinColumn(name="address_id")}, + * inverseJoinColumns={@ORM\JoinColumn(name="geographical_unit_id")} + * ) + */ + private Collection $geographicalUnits; + /** * @var int * @@ -104,8 +123,9 @@ class Address * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") * @Groups({"write"}) + * @readonly */ - private $id; + private ?int $id = null; /** * True if the address is a "no address", aka homeless person, ... @@ -190,6 +210,7 @@ class Address public function __construct() { $this->validFrom = new DateTime(); + $this->geographicalUnits = new ArrayCollection(); } public static function createFromAddress(Address $original): Address @@ -273,6 +294,14 @@ class Address return $this->floor; } + /** + * @return Collection|GeographicalUnit[] + */ + public function getGeographicalUnits(): Collection + { + return $this->geographicalUnits; + } + /** * Get id. * diff --git a/src/Bundle/ChillMainBundle/migrations/Version20221114105345.php b/src/Bundle/ChillMainBundle/migrations/Version20221114105345.php new file mode 100644 index 000000000..8bc75ac29 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20221114105345.php @@ -0,0 +1,42 @@ +addSql('DROP MATERIALIZED VIEW view_chill_main_address_geographical_unit'); + } + + public function getDescription(): string + { + return 'Create materialized view to store GeographicalUnitAddress'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE MATERIALIZED VIEW view_chill_main_address_geographical_unit (address_id, geographical_unit_id) AS + SELECT + address.id AS address_id, + geographical_unit.id AS geographical_unit_id + FROM chill_main_address AS address + JOIN chill_main_geographical_unit AS geographical_unit ON ST_CONTAINS(geographical_unit.geom, address.point) + '); + + $this->addSql('CREATE INDEX IDX_BD42692CF5B7AF75 ON view_chill_main_address_geographical_unit (address_id)'); + $this->addSql('CREATE INDEX IDX_BD42692CDAA4DAB8 ON view_chill_main_address_geographical_unit (geographical_unit_id)'); + } +} From cf6430ae9badcbc801f78c10ec062c6bfd1c5c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 14:22:48 +0100 Subject: [PATCH 85/99] Feature: Adapt geographical unit filters and aggregator to use the materialized view, instead of geographical computation (improve performance) --- .../GeographicalUnitStatAggregator.php | 64 ++++++++----------- .../GeographicalUnitAggregator.php | 4 +- .../GeographicalUnitStatFilter.php | 10 +-- .../PersonFilters/GeographicalUnitFilter.php | 4 +- .../translations/messages.fr.yml | 2 + 5 files changed, 33 insertions(+), 51 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php index 891ce63e0..9dec0f116 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\ChillDateType; @@ -26,7 +25,6 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use UnexpectedValueException; -use function in_array; final class GeographicalUnitStatAggregator implements AggregatorInterface { @@ -49,57 +47,49 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - if (!in_array('acp_geog_agg_location_history', $qb->getAllAliases(), true)) { - $qb->leftJoin('acp.locationHistories', 'acp_geog_agg_location_history'); + $qb->leftJoin('acp.locationHistories', 'acp_geog_agg_location_history'); - $qb->andWhere( - $qb->expr()->andX( - 'acp_geog_agg_location_history.startDate <= :acp_geog_aggregator_date', - $qb->expr()->orX( + $qb->andWhere( + $qb->expr()->andX( + 'acp_geog_agg_location_history.startDate <= :acp_geog_aggregator_date', + $qb->expr()->orX( 'acp_geog_agg_location_history.endDate IS NULL', 'acp_geog_agg_location_history.endDate > :acp_geog_aggregator_date' ) - ) - ); + ) + ); - $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); - } + $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); // link between location history and person - if (!in_array('acp_geog_agg_address_person_location', $qb->getAllAliases(), true)) { - $qb->leftJoin( - PersonHouseholdAddress::class, - 'acp_geog_agg_address_person_location', - Join::WITH, - $qb->expr()->andX( - 'IDENTITY(acp_geog_agg_address_person_location.person) = IDENTITY(acp_geog_agg_location_history.personLocation)', - 'acp_geog_agg_address_person_location.validFrom < :acp_geog_aggregator_date', - $qb->expr()->orX( + $qb->leftJoin( + PersonHouseholdAddress::class, + 'acp_geog_agg_address_person_location', + Join::WITH, + $qb->expr()->andX( + 'IDENTITY(acp_geog_agg_address_person_location.person) = IDENTITY(acp_geog_agg_location_history.personLocation)', + 'acp_geog_agg_address_person_location.validFrom < :acp_geog_aggregator_date', + $qb->expr()->orX( 'acp_geog_agg_address_person_location.validTo > :acp_geog_aggregator_date', $qb->expr()->isNull('acp_geog_agg_address_person_location.validTo') ) - ) - ); + ) + ); - $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); - } + $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); // we finally find an address - if (!in_array('acp_geog_agg_address', $qb->getAllAliases(), true)) { - $qb->leftJoin( - Address::class, - 'acp_geog_agg_address', - Join::WITH, - 'COALESCE(IDENTITY(acp_geog_agg_address_person_location.address), IDENTITY(acp_geog_agg_location_history.addressLocation)) = acp_geog_agg_address.id' - ); - } + $qb->leftJoin( + Address::class, + 'acp_geog_agg_address', + Join::WITH, + 'COALESCE(IDENTITY(acp_geog_agg_address_person_location.address), IDENTITY(acp_geog_agg_location_history.addressLocation)) = acp_geog_agg_address.id' + ); // and we do a join with units $qb->leftJoin( - GeographicalUnit::class, - 'acp_geog_units', - Join::WITH, - 'ST_CONTAINS(acp_geog_units.geom, acp_geog_agg_address.point) = TRUE' + 'acp_geog_agg_address.geographicalUnits', + 'acp_geog_units' ); $qb->andWhere($qb->expr()->eq('acp_geog_units.layer', ':acp_geog_unit_layer')); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php index 3513625e9..87fe6abb2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php @@ -11,7 +11,6 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; -use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\ChillDateType; @@ -19,7 +18,6 @@ use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; -use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -49,7 +47,7 @@ class GeographicalUnitAggregator implements AggregatorInterface $qb ->leftJoin('person.householdAddresses', 'person_geog_agg_current_household_address') ->leftJoin('person_geog_agg_current_household_address.address', 'person_geog_agg_address') - ->leftJoin(GeographicalUnit::class, 'person_geog_agg_geog_unit', Join::WITH, 'ST_CONTAINS(person_geog_agg_geog_unit.geom, person_geog_agg_address.point) = TRUE') + ->leftJoin('person_geog_agg_address.geographicalUnits', 'person_geog_agg_geog_unit') ->andWhere( $qb->expr()->orX( $qb->expr()->isNull('person_geog_agg_current_household_address'), diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php index ee420e63e..67355aeca 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\ChillDateType; @@ -23,7 +22,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; @@ -33,8 +31,6 @@ use Symfony\Component\Form\FormBuilderInterface; */ class GeographicalUnitStatFilter implements FilterInterface { - private EntityManagerInterface $em; - private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; private GeographicalUnitRepositoryInterface $geographicalUnitRepository; @@ -42,12 +38,10 @@ class GeographicalUnitStatFilter implements FilterInterface private TranslatableStringHelperInterface $translatableStringHelper; public function __construct( - EntityManagerInterface $em, GeographicalUnitRepositoryInterface $geographicalUnitRepository, GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, TranslatableStringHelperInterface $translatableStringHelper ) { - $this->em = $em; $this->geographicalUnitRepository = $geographicalUnitRepository; $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; @@ -68,7 +62,7 @@ class GeographicalUnitStatFilter implements FilterInterface WITH IDENTITY(acp_geog_filter_location_history.personLocation) = IDENTITY(acp_geog_filter_address_person_location.person) LEFT JOIN ' . Address::class . ' acp_geog_filter_address WITH COALESCE(IDENTITY(acp_geog_filter_address_person_location.address), IDENTITY(acp_geog_filter_location_history.addressLocation)) = acp_geog_filter_address.id - LEFT JOIN ' . GeographicalUnit::class . ' acp_geog_filter_units WITH ST_CONTAINS(acp_geog_filter_units.geom, acp_geog_filter_address.point) = TRUE + LEFT JOIN acp_geog_filter_address.geographicalUnits acp_geog_filter_units WHERE (acp_geog_filter_location_history.startDate <= :acp_geog_filter_date AND ( acp_geog_filter_location_history.endDate IS NULL OR acp_geog_filter_location_history.endDate < :acp_geog_filter_date @@ -120,7 +114,7 @@ class GeographicalUnitStatFilter implements FilterInterface { return ['Filtered by geographic unit: computed at %date%, only in %units%', [ '%date%' => $data['date_calc']->format('d-m-Y'), - '%units' => implode( + '%units%' => implode( ', ', array_map( function (SimpleGeographicalUnitDTO $item) { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php index 03d9ab568..3d539a442 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php @@ -11,7 +11,6 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\PersonFilters; -use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; @@ -53,8 +52,7 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface 'SELECT 1 FROM ' . PersonHouseholdAddress::class . ' person_filter_geog_person_household_address JOIN person_filter_geog_person_household_address.address person_filter_geog_address - JOIN ' . GeographicalUnit::class . ' person_filter_geog_unit - WITH ST_CONTAINS(person_filter_geog_unit.geom, person_filter_geog_address.point) = TRUE + JOIN person_filter_geog_address.geographicalUnits person_filter_geog_unit WHERE person_filter_geog_person_household_address.validFrom <= :person_filter_geog_date AND diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 0b53bd7a5..7c9afba48 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -586,6 +586,8 @@ end period date: Date de fin de la période Filter by current evaluations: Filtrer les évaluations en cours "Filtered by current evaluations": "Filtré: uniquement les évaluations en cours" +'Filtered by geographic unit: computed at %date%, only in %units%': 'Filtré par unité géographique: adresse le %date%, seulement les unités %units%' + ## social actions filters/aggr Filter by treating agent scope: Filtrer les actions par service de l'agent traitant "Filtered by treating agent scope: only %scopes%": "Filtré par service de l'agent traitant: uniquement %scopes%" From 1f3dd00d815520dab82d4e2cb4db23fdd5e01599 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 14 Nov 2022 12:31:13 +0100 Subject: [PATCH 86/99] improve flex positionning for list exports cards --- .../Resources/public/chill/chillmain.scss | 14 +++++++---- .../Resources/views/Export/layout.html.twig | 24 +++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss index 5c302bf83..7cd3f5479 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss @@ -518,8 +518,14 @@ div.v-toast { z-index: 10000!important; } -div.grouped { - padding: 1em; - border: 1px solid black; - margin-bottom: 2em; +// export index page +div.exports-list { + div.flex-bloc .item-bloc { + flex-basis: 33%; + @include media-breakpoint-down(lg) { flex-basis: 50%; } + @include media-breakpoint-down(sm) { flex-basis: 100%; } + p:last-child { + margin-top: auto; + } + } } \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig index 5ce433535..b86f617b4 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig @@ -25,25 +25,23 @@ {{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'common'}) }} -
+
{% for group, exports in grouped_exports %}{% if group != '_' %}

{{ group|trans }}

-
+
{% for export_alias, export in exports %} -
-
-
-

{{ export.title|trans }}

-

{{ export.description|trans }}

-

- - {{ 'Create an export'|trans }} - -

-
+
+
+

{{ export.title|trans }}

+

{{ export.description|trans }}

+

+ + {{ 'Create an export'|trans }} + +

{% endfor %} From 68bfb082fc9a482c268fb9100c23c5a2b15bae10 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 14 Nov 2022 15:38:14 +0100 Subject: [PATCH 87/99] chill-bundles#25: replace ChillDateType by PickRollingDateType batch/serial replacing untested --- .../Export/Filter/ActivityDateFilter.php | 34 +++++++++++------ .../src/Export/Filter/ByDateFilter.php | 34 +++++++++++------ .../Export/Filter/BetweenDatesFilter.php | 33 ++++++++++------ .../GeographicalUnitStatAggregator.php | 24 ++++++++---- .../ReferrerAggregator.php | 20 ++++++---- .../ReferrerScopeAggregator.php | 20 ++++++---- .../ChildrenNumberAggregator.php | 20 ++++++---- .../CompositionAggregator.php | 20 ++++++---- .../ByHouseholdCompositionAggregator.php | 24 ++++++++---- .../GeographicalUnitAggregator.php | 20 ++++++---- .../HouseholdPositionAggregator.php | 19 +++++++--- .../ActiveOnDateFilter.php | 23 +++++++---- .../ActiveOneDayBetweenDatesFilter.php | 33 ++++++++++------ .../GeographicalUnitStatFilter.php | 22 +++++++---- .../HasNoReferrerFilter.php | 25 ++++++++---- .../HasTemporaryLocationFilter.php | 22 ++++++++--- .../ReferrerFilter.php | 23 +++++++---- .../AccompanyingCourseFilters/StepFilter.php | 8 +++- .../UserJobFilter.php | 20 ++++++---- .../UserScopeFilter.php | 20 ++++++---- .../EvaluationFilters/ByEndDateFilter.php | 33 ++++++++++------ .../EvaluationFilters/ByStartDateFilter.php | 33 ++++++++++------ .../HouseholdFilters/CompositionFilter.php | 22 +++++++---- .../Export/Filter/PersonFilters/AgeFilter.php | 19 +++++++--- .../Filter/PersonFilters/BirthdateFilter.php | 38 +++++++++++++------ .../PersonFilters/DeadOrAliveFilter.php | 21 +++++++--- .../Filter/PersonFilters/DeathdateFilter.php | 33 +++++++++++----- .../PersonFilters/GeographicalUnitFilter.php | 22 +++++++---- .../ResidentialAddressAtThirdpartyFilter.php | 24 ++++++++---- .../ResidentialAddressAtUserFilter.php | 21 +++++++--- .../Export/Filter/ReportDateFilter.php | 33 +++++++++++----- 31 files changed, 512 insertions(+), 251 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php index 1f3a52cc5..edfa9b030 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -13,9 +13,10 @@ namespace Chill\ActivityBundle\Export\Filter; use Chill\ActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Form\Type\Export\FilterType; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -26,11 +27,16 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ActivityDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + protected TranslatorInterface $translator; - public function __construct(TranslatorInterface $translator) - { + public function __construct( + TranslatorInterface $translator, + RollingDateConverterInterface $rollingDateConverter + ) { $this->translator = $translator; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -54,8 +60,12 @@ class ActivityDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('date_from', $data['date_from']); - $qb->setParameter('date_to', $data['date_to']); + $qb->setParameter('date_from', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('date_to', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn(): string @@ -66,13 +76,13 @@ class ActivityDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', ChillDateType::class, [ + ->add('date_from', PickRollingDateType::class, [ 'label' => 'Activities after this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) - ->add('date_to', ChillDateType::class, [ + ->add('date_to', PickRollingDateType::class, [ 'label' => 'Activities before this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { @@ -121,8 +131,8 @@ class ActivityDateFilter implements FilterInterface return [ 'Filtered by date of activity: only between %date_from% and %date_to%', [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), + '%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ], ]; } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index a7595281d..fca4dece8 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -13,9 +13,10 @@ namespace Chill\AsideActivityBundle\Export\Filter; use Chill\AsideActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Form\Type\Export\FilterType; -use DateTime; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -26,11 +27,16 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ByDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + protected TranslatorInterface $translator; - public function __construct(TranslatorInterface $translator) - { + public function __construct( + RollingDateConverterInterface $rollingDateConverter, + TranslatorInterface $translator + ) { $this->translator = $translator; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -54,8 +60,12 @@ class ByDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('date_from', $data['date_from']); - $qb->setParameter('date_to', $data['date_to']); + $qb->setParameter('date_from', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('date_to', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn(): string @@ -66,13 +76,13 @@ class ByDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', ChillDateType::class, [ + ->add('date_from', PickRollingDateType::class, [ 'label' => 'export.filter.Aside activities after this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) - ->add('date_to', ChillDateType::class, [ + ->add('date_to', PickRollingDateType::class, [ 'label' => 'export.filter.Aside activities before this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { @@ -119,8 +129,8 @@ class ByDateFilter implements FilterInterface public function describeAction($data, $format = 'string'): array { return ['export.filter.Filtered by aside activities between %dateFrom% and %dateTo%', [ - '%dateFrom%' => $data['date_from']->format('d-m-Y'), - '%dateTo%' => $data['date_to']->format('d-m-Y'), + '%dateFrom%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%dateTo%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php index 65707d9e4..01bfad033 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php @@ -13,15 +13,22 @@ namespace Chill\CalendarBundle\Export\Filter; use Chill\CalendarBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; -use DateTime; -use Doctrine\DBAL\Types\Types; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class BetweenDatesFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -43,9 +50,13 @@ class BetweenDatesFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('dateFrom', $data['date_from'], Types::DATE_MUTABLE); + $qb->setParameter('dateFrom', + $this->rollingDateConverter->convert($data['date_from']) + ); // modify dateTo so that entire day is also taken into account up until the beginning of the next day. - $qb->setParameter('dateTo', $data['date_to']->modify('+1 day'), Types::DATE_MUTABLE); + $qb->setParameter('dateTo', + $this->rollingDateConverter->convert($data['date_to'])->modify('+1 day') + ); } public function applyOn(): string @@ -56,19 +67,19 @@ class BetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_from', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) - ->add('date_to', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_to', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by appointments between %dateFrom% and %dateTo%', [ - '%dateFrom%' => $data['date_from']->format('d-m-Y'), - '%dateTo%' => $data['date_to']->format('d-m-Y'), + '%dateFrom%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%dateTo%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php index 891ce63e0..59a39ab12 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php @@ -15,12 +15,13 @@ use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -34,12 +35,16 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface private TranslatableStringHelperInterface $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -62,7 +67,9 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface ) ); - $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); + $qb->setParameter('acp_geog_aggregator_date', + $this->rollingDateConverter->convert($data['date_calc']) + ); } // link between location history and person @@ -81,7 +88,9 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface ) ); - $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); + $qb->setParameter('acp_geog_aggregator_date', + $this->rollingDateConverter->convert($data['date_calc']) + ); } // we finally find an address @@ -122,11 +131,10 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_calc', ChillDateType::class, [ + ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new DateTimeImmutable('today'), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('level', EntityType::class, [ 'label' => 'Geographical layer', diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php index 327b76a65..84da976c6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php @@ -12,11 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\UserRepository; use Chill\MainBundle\Templating\Entity\UserRender; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -30,12 +31,16 @@ final class ReferrerAggregator implements AggregatorInterface private UserRepository $userRepository; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( UserRepository $userRepository, - UserRender $userRender + UserRender $userRender, + RollingDateConverterInterface $rollingDateConverter ) { $this->userRepository = $userRepository; $this->userRender = $userRender; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -61,7 +66,9 @@ final class ReferrerAggregator implements AggregatorInterface ) ) ) - ->setParameter(self::P, $data['date_calc']); + ->setParameter(self::P, + $this->rollingDateConverter->convert($data['date_calc']) + ); } public function applyOn(): string @@ -72,9 +79,8 @@ final class ReferrerAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_calc', ChillDateType::class, [ - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + ->add('date_calc', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.aggregator.course.by_referrer.Computation date for referrer', 'required' => true, ]); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php index 506bee66f..16ff76e3d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php @@ -12,11 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\Form\FormBuilderInterface; @@ -29,12 +30,16 @@ class ReferrerScopeAggregator implements AggregatorInterface private TranslatableStringHelperInterface $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( ScopeRepositoryInterface $scopeRepository, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->scopeRepository = $scopeRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -64,7 +69,9 @@ class ReferrerScopeAggregator implements AggregatorInterface ) ) ) - ->setParameter($dateCalc, $data['date_calc']); + ->setParameter($dateCalc, + $this->rollingDateConverter->convert($data['date_calc']) + ); // add groups $qb @@ -79,9 +86,8 @@ class ReferrerScopeAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_calc', ChillDateType::class, [ - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + $builder->add('date_calc', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.aggregator.course.by_user_scope.Computation date for referrer', 'required' => true, ]); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php index 8024cb08b..aa2e9b4b6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php @@ -12,10 +12,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\HouseholdAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -26,10 +26,14 @@ class ChildrenNumberAggregator implements AggregatorInterface { private TranslatorInterface $translator; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( - TranslatorInterface $translator + TranslatorInterface $translator, + RollingDateConverterInterface $rollingDateConverter ) { $this->translator = $translator; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -55,7 +59,9 @@ class ChildrenNumberAggregator implements AggregatorInterface ->addSelect('composition_children.numberOfChildren AS childrennumber_aggregator') ->addGroupBy('childrennumber_aggregator'); - $qb->setParameter('ondate_composition_children', $data['on_date'], Types::DATE_MUTABLE); + $qb->setParameter('ondate_composition_children', + $this->rollingDateConverter->convert($data['on_date']) + ); } public function applyOn(): string @@ -65,8 +71,8 @@ class ChildrenNumberAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', ChillDateType::class, [ - 'data' => new DateTime('now'), + $builder->add('on_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php index ad7b7030f..1917a51b3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\HouseholdAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepository; -use DateTime; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -29,12 +29,16 @@ class CompositionAggregator implements AggregatorInterface private HouseholdCompositionTypeRepository $typeRepository; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( HouseholdCompositionTypeRepository $typeRepository, - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->typeRepository = $typeRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -60,7 +64,9 @@ class CompositionAggregator implements AggregatorInterface ->addSelect('IDENTITY(composition_type.householdCompositionType) AS composition_aggregator') ->addGroupBy('composition_aggregator'); - $qb->setParameter('ondate_composition_type', $data['on_date'], Types::DATE_MUTABLE); + $qb->setParameter('ondate_composition_type', + $this->rollingDateConverter->convert($data['on_date']) + ); } public function applyOn(): string @@ -70,8 +76,8 @@ class CompositionAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', ChillDateType::class, [ - 'data' => new DateTime('now'), + $builder->add('on_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php index 7a1aaaa49..576f52626 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php @@ -12,12 +12,13 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\HouseholdComposition; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepositoryInterface; -use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -30,10 +31,16 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface private TranslatableStringHelperInterface $translatableStringHelper; - public function __construct(HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository, TranslatableStringHelperInterface $translatableStringHelper) - { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter, + HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository, + TranslatableStringHelperInterface $translatableStringHelper + ) { $this->householdCompositionTypeRepository = $householdCompositionTypeRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -71,7 +78,9 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface ) ) ->addSelect("IDENTITY({$p}_compo.householdCompositionType) AS {$p}_select") - ->setParameter("{$p}_date", $data['date_calc']) + ->setParameter("{$p}_date", + $this->rollingDateConverter->convert($data['date_calc']) + ) ->addGroupBy("{$p}_select"); } @@ -82,10 +91,9 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_calc', ChillDateType::class, [ + $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'export.aggregator.person.by_household_composition.Calc date', - 'input_format' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php index 3513625e9..dd6f10035 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php @@ -14,11 +14,12 @@ namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use LogicException; @@ -31,12 +32,16 @@ class GeographicalUnitAggregator implements AggregatorInterface private TranslatableStringHelperInterface $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -68,7 +73,9 @@ class GeographicalUnitAggregator implements AggregatorInterface $qb->expr()->in('person_geog_agg_geog_unit.layer', ':person_geog_agg_layers') ) ) - ->setParameter('person_geog_agg_date', $data['date_calc']) + ->setParameter('person_geog_agg_date', + $this->rollingDateConverter->convert($data['date_calc']) + ) ->setParameter('person_geog_agg_layers', $data['level']) ->addSelect('person_geog_agg_geog_unit.unitName AS geog_unit_name') ->addSelect('person_geog_agg_geog_unit.unitRefId AS geog_unit_key') @@ -84,11 +91,10 @@ class GeographicalUnitAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_calc', ChillDateType::class, [ + ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Address valid at this date', 'required' => true, - 'data' => new DateTimeImmutable('today'), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('level', EntityType::class, [ 'label' => 'Geographical layer', diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php index 2001466ab..0d986bdea 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php @@ -13,12 +13,13 @@ namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Repository\Household\PositionRepository; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -34,14 +35,18 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl private TranslatorInterface $translator; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, - PositionRepository $positionRepository + PositionRepository $positionRepository, + RollingDateConverterInterface $rollingDateConverter ) { $this->translator = $translator; $this->positionRepository = $positionRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -67,7 +72,9 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl ) )); - $qb->setParameter('date', $data['date_position']); + $qb->setParameter('date', + $this->rollingDateConverter->convert($data['date_position']) + ); $qb->addSelect('IDENTITY(householdmember.position) AS household_position_aggregator'); $qb->addGroupBy('household_position_aggregator'); @@ -80,9 +87,9 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_position', ChillDateType::class, [ + $builder->add('date_position', PickRollingDateType::class, [ 'label' => 'Household position in relation to this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php index 7fa92c0ae..55fe56d59 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php @@ -12,16 +12,23 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class ActiveOnDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -46,7 +53,9 @@ class ActiveOnDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('ondate', $data['on_date'], Types::DATE_MUTABLE); + $qb->setParameter('ondate', + $this->rollingDateConverter->convert($data['on_date']) + ); } public function applyOn(): string @@ -57,15 +66,15 @@ class ActiveOnDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('on_date', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('on_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by actives courses: active on %ondate%', [ - '%ondate%' => $data['on_date']->format('d-m-Y'), + '%ondate%' => $this->rollingDateConverter->convert($data['on_date'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php index bf6698f60..4d1a9ad23 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php @@ -12,15 +12,22 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class ActiveOneDayBetweenDatesFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -31,8 +38,12 @@ class ActiveOneDayBetweenDatesFilter implements FilterInterface $clause = "OVERLAPSI (acp.openingDate, acp.closingDate), (:datefrom, :dateto) = 'TRUE'"; $qb->andWhere($clause); - $qb->setParameter('datefrom', $data['date_from'], Types::DATE_MUTABLE); - $qb->setParameter('dateto', $data['date_to'], Types::DATE_MUTABLE); + $qb->setParameter('datefrom', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('dateto', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn(): string @@ -43,19 +54,19 @@ class ActiveOneDayBetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_from', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) - ->add('date_to', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_to', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by actives courses: at least one day between %datefrom% and %dateto%', [ - '%datefrom%' => $data['date_from']->format('d-m-Y'), - '%dateto%' => $data['date_to']->format('d-m-Y'), + '%datefrom%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%dateto%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php index ee420e63e..55e710f8e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php @@ -15,14 +15,15 @@ use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -41,16 +42,20 @@ class GeographicalUnitStatFilter implements FilterInterface private TranslatableStringHelperInterface $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( EntityManagerInterface $em, GeographicalUnitRepositoryInterface $geographicalUnitRepository, GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->em = $em; $this->geographicalUnitRepository = $geographicalUnitRepository; $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -83,7 +88,9 @@ class GeographicalUnitStatFilter implements FilterInterface $qb ->andWhere($qb->expr()->exists($subQueryDql)) - ->setParameter('acp_geog_filter_date', $data['date_calc']) + ->setParameter('acp_geog_filter_date', + $this->rollingDateConverter->convert($data['date_calc']) + ) ->setParameter('acp_geog_filter_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); } @@ -95,11 +102,10 @@ class GeographicalUnitStatFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_calc', ChillDateType::class, [ + ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new DateTimeImmutable('today'), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', @@ -119,7 +125,7 @@ class GeographicalUnitStatFilter implements FilterInterface public function describeAction($data, $format = 'string'): array { return ['Filtered by geographic unit: computed at %date%, only in %units%', [ - '%date%' => $data['date_calc']->format('d-m-Y'), + '%date%' => $this->rollingDateConverter->convert($data['date_calc'])->format('d-m-Y'), '%units' => implode( ', ', array_map( diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index 303c789af..ff30b6312 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -12,16 +12,24 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class HasNoReferrerFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -41,7 +49,9 @@ class HasNoReferrerFilter implements FilterInterface AND uh.accompanyingPeriod = acp ) ') - ->setParameter('has_no_referrer_filter_date', $data['calc_date'], Types::DATE_IMMUTABLE); + ->setParameter('has_no_referrer_filter_date', + $this->rollingDateConverter->convert($data['calc_date']) + ); } public function applyOn(): string @@ -52,17 +62,16 @@ class HasNoReferrerFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('calc_date', ChillDateType::class, [ + ->add('calc_date', PickRollingDateType::class, [ 'label' => 'Has no referrer on this date', - 'data' => new DateTimeImmutable(), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered acp which has no referrer on date: %date%', [ - '%date%' => $data['calc_date']->format('d-m-Y'), + '%date%' => $this->rollingDateConverter->convert($data['calc_date'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 2ae1ad2a0..3dfbea9c2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -12,9 +12,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use LogicException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -22,6 +23,14 @@ use Symfony\Component\Form\FormBuilderInterface; class HasTemporaryLocationFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -33,7 +42,9 @@ class HasTemporaryLocationFilter implements FilterInterface ->join('acp.locationHistories', 'acp_having_temporarily_location') ->andWhere('acp_having_temporarily_location.startDate <= :acp_having_temporarily_location_date AND (acp_having_temporarily_location.endDate IS NULL OR acp_having_temporarily_location.endDate > :acp_having_temporarily_location_date)') - ->setParameter('acp_having_temporarily_location_date', $data['calc_date']); + ->setParameter('acp_having_temporarily_location_date', + $this->rollingDateConverter->convert($data['calc_date']) + ); switch ($data['having_temporarily']) { case true: @@ -77,10 +88,9 @@ class HasTemporaryLocationFilter implements FilterInterface } }, ]) - ->add('calc_date', ChillDateType::class, [ + ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.filter.course.having_temporarily.Calculation date', - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php index 7d1aabc22..5e1ad18b9 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php @@ -12,11 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\MainBundle\Templating\Entity\UserRender; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -30,9 +31,14 @@ class ReferrerFilter implements FilterInterface private UserRender $userRender; - public function __construct(UserRender $userRender) - { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + UserRender $userRender, + RollingDateConverterInterface $rollingDateConverter + ) { $this->userRender = $userRender; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -57,7 +63,9 @@ class ReferrerFilter implements FilterInterface $qb->expr()->in(self::A . '.user', ':' . self::PU) ) ->setParameter(self::PU, $data['accepted_referrers']) - ->setParameter(self::P, $data['date_calc']); + ->setParameter(self::P, + $this->rollingDateConverter->convert($data['date_calc']) + ); } public function applyOn(): string @@ -71,9 +79,8 @@ class ReferrerFilter implements FilterInterface ->add('accepted_referrers', PickUserDynamicType::class, [ 'multiple' => true, ]) - ->add('date_calc', ChillDateType::class, [ - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + ->add('date_calc', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_referrer.Computation date for referrer', 'required' => true, ]); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php index 0c9b28e8c..240b093b5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/StepFilter.php @@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Export\Declarations; @@ -43,8 +44,10 @@ class StepFilter implements FilterInterface */ private $translator; - public function __construct(RollingDateConverterInterface $rollingDateConverter, TranslatorInterface $translator) - { + public function __construct( + RollingDateConverterInterface $rollingDateConverter, + TranslatorInterface $translator + ) { $this->rollingDateConverter = $rollingDateConverter; $this->translator = $translator; } @@ -94,6 +97,7 @@ class StepFilter implements FilterInterface ]) ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.acp.filter.by_step.date_calc', + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php index a18442c2a..fadc5d295 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php @@ -14,11 +14,12 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\UserJobRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; @@ -40,14 +41,18 @@ class UserJobFilter implements FilterInterface private UserJobRepositoryInterface $userJobRepository; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( Security $security, TranslatableStringHelper $translatableStringHelper, - UserJobRepositoryInterface $userJobRepository + UserJobRepositoryInterface $userJobRepository, + RollingDateConverterInterface $rollingDateConverter ) { $this->security = $security; $this->translatableStringHelper = $translatableStringHelper; $this->userJobRepository = $userJobRepository; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -68,7 +73,9 @@ class UserJobFilter implements FilterInterface ) ) ) - ->setParameter(self::P, $data['date_calc']) + ->setParameter(self::P, + $this->rollingDateConverter->convert($data['date_calc']) + ) ->join(self::A . '.user', self::AU) ->andWhere( $qb->expr()->in(self::AU . '.userJob', ':' . self::PJ) @@ -92,9 +99,8 @@ class UserJobFilter implements FilterInterface 'choice_label' => fn (UserJob $job) => $this->translatableStringHelper->localize($job->getLabel()), 'label' => 'Job', ]) - ->add('date_calc', ChillDateType::class, [ - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + ->add('date_calc', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_user_scope.Computation date for referrer', 'required' => true, ]); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php index 48a97f9f7..3fcf4f87e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php @@ -14,11 +14,12 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; @@ -40,14 +41,18 @@ class UserScopeFilter implements FilterInterface private TranslatableStringHelper $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( ScopeRepositoryInterface $scopeRepository, Security $security, - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->scopeRepository = $scopeRepository; $this->security = $security; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -68,7 +73,9 @@ class UserScopeFilter implements FilterInterface ) ) ) - ->setParameter(self::P, $data['date_calc']) + ->setParameter(self::P, + $this->rollingDateConverter->convert($data['date_calc']) + ) ->join(self::A . '.user', self::AU) ->andWhere( $qb->expr()->in(self::AU . '.mainScope', ':' . self::PS) @@ -91,9 +98,8 @@ class UserScopeFilter implements FilterInterface 'multiple' => true, 'expanded' => true, ]) - ->add('date_calc', ChillDateType::class, [ - 'input' => 'datetime_immutable', - 'data' => new DateTimeImmutable('now'), + ->add('date_calc', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_user_scope.Computation date for referrer', 'required' => true, ]); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index f828da109..5021da1bc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -12,15 +12,23 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class ByEndDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -30,8 +38,12 @@ class ByEndDateFilter implements FilterInterface { $qb ->andWhere('workeval.endDate BETWEEN :work_eval_by_end_date_start_date and :work_eval_by_end_date_end_date') - ->setParameter('work_eval_by_end_date_start_date', $data['start_date'], Types::DATE_IMMUTABLE) - ->setParameter('work_eval_by_end_date_end_date', $data['end_date'], Types::DATE_IMMUTABLE); + ->setParameter('work_eval_by_end_date_start_date', + $this->rollingDateConverter->convert($data['start_date']) + ) + ->setParameter('work_eval_by_end_date_end_date', + $this->rollingDateConverter->convert($data['end_date']) + ); } public function applyOn(): string @@ -42,23 +54,22 @@ class ByEndDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder): void { $builder - ->add('start_date', ChillDateType::class, [ + ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new DateTimeImmutable('1 year ago'), + 'data' => new RollingDate(RollingDate::T_TODAY, new DateTimeImmutable('1 year ago')), 'input' => 'datetime_immutable', ]) - ->add('end_date', ChillDateType::class, [ + ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', - 'data' => new DateTimeImmutable(), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by end date: between %start_date% and %end_date%', [ - '%start_date%' => $data['start_date']->format('d-m-Y'), - '%end_date%' => $data['end_date']->format('d-m-Y'), + '%start_date%' => $this->rollingDateConverter->convert($data['start_date'])->format('d-m-Y'), + '%end_date%' => $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index f12b5e805..c5c4c8899 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -12,15 +12,23 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\EvaluationFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; use DateTimeImmutable; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; class ByStartDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -30,8 +38,12 @@ class ByStartDateFilter implements FilterInterface { $qb ->andWhere('workeval.startDate BETWEEN :work_eval_by_start_date_start_date and :work_eval_by_start_date_end_date') - ->setParameter('work_eval_by_start_date_start_date', $data['start_date'], Types::DATE_IMMUTABLE) - ->setParameter('work_eval_by_start_date_end_date', $data['end_date'], Types::DATE_IMMUTABLE); + ->setParameter('work_eval_by_start_date_start_date', + $this->rollingDateConverter->convert($data['start_date']) + ) + ->setParameter('work_eval_by_start_date_end_date', + $this->rollingDateConverter->convert($data['end_date']) + ); } public function applyOn(): string @@ -42,23 +54,22 @@ class ByStartDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder): void { $builder - ->add('start_date', ChillDateType::class, [ + ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new DateTimeImmutable('1 year ago'), + 'data' => new RollingDate(RollingDate::T_TODAY, new DateTimeImmutable('1 year ago')), 'input' => 'datetime_immutable', ]) - ->add('end_date', ChillDateType::class, [ + ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', - 'data' => new DateTimeImmutable(), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } public function describeAction($data, $format = 'string'): array { return ['Filtered by start date: between %start_date% and %end_date%', [ - '%start_date%' => $data['start_date']->format('d-m-Y'), - '%end_date%' => $data['end_date']->format('d-m-Y'), + '%start_date%' => $this->rollingDateConverter->convert($data['start_date'])->format('d-m-Y'), + '%end_date%' => $this->rollingDateConverter->convert($data['end_date'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php index 3ff8cb63e..e9b06d6af 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php @@ -12,12 +12,12 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\HouseholdFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Household\HouseholdCompositionType; use Chill\PersonBundle\Export\Declarations; -use DateTime; -use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -28,10 +28,14 @@ class CompositionFilter implements FilterInterface { private TranslatableStringHelper $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -58,7 +62,9 @@ class CompositionFilter implements FilterInterface $qb->andWhere($whereClause); $qb->setParameter('compositions', $data['accepted_composition']); - $qb->setParameter('ondate_composition_type_filter', $data['on_date'], Types::DATE_MUTABLE); + $qb->setParameter('ondate_composition_type_filter', + $this->rollingDateConverter->convert($data['on_date']) + ); } public function applyOn(): string @@ -79,8 +85,8 @@ class CompositionFilter implements FilterInterface 'multiple' => true, 'expanded' => true, ]) - ->add('on_date', ChillDateType::class, [ - 'data' => new DateTime('now'), + ->add('on_date', PickRollingDateType::class, [ + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -96,7 +102,7 @@ class CompositionFilter implements FilterInterface return ['Filtered by composition: only %compositions% on %ondate%', [ '%compositions%' => implode(', ', $compositions), - '%ondate%' => $data['on_date']->format('d-m-Y'), + '%ondate%' => $this->rollingDateConverter->convert($data['on_date'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php index 218ae483e..0bf175ce4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php @@ -13,10 +13,11 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; use DateInterval; -use DateTimeImmutable; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\IntegerType; @@ -25,6 +26,13 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; class AgeFilter implements ExportElementValidatedInterface, FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -36,7 +44,7 @@ class AgeFilter implements ExportElementValidatedInterface, FilterInterface $min = null !== $data['min_age'] ? $data['min_age'] : 0; $max = null !== $data['max_age'] ? $data['max_age'] : 150; - $calc = $data['date_calc']; + $calc = $this->rollingDateConverter->convert($data['date_calc']); $minDate = $calc->sub(new DateInterval('P' . $max . 'Y')); $maxDate = $calc->sub(new DateInterval('P' . $min . 'Y')); @@ -78,10 +86,9 @@ class AgeFilter implements ExportElementValidatedInterface, FilterInterface 'label' => 'Maximum age', ]); - $builder->add('date_calc', ChillDateType::class, [ + $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Calculate age in relation to this date', - 'data' => new DateTimeImmutable('now'), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php index aaa88fb7b..24883b681 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php @@ -13,20 +13,30 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; class BirthdateFilter implements ExportElementValidatedInterface, FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct(RollingDateConverterInterface $rollingDateConverter) + { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; } - public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); $clause = $qb->expr()->between( @@ -42,8 +52,12 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac } $qb->add('where', $where); - $qb->setParameter('date_from', $data['date_from']); - $qb->setParameter('date_to', $data['date_to']); + $qb->setParameter('date_from', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('date_to', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn() @@ -51,16 +65,16 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac return Declarations::PERSON_TYPE; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, [ + $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Born after this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); - $builder->add('date_to', ChillDateType::class, [ + $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Born before this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -68,8 +82,8 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac { return ['Filtered by person\'s birthdate: ' . 'between %date_from% and %date_to%', [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), + '%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ], ]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php index e317d4a04..384d6698a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php @@ -12,9 +12,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -22,6 +23,14 @@ use Symfony\Component\Form\FormBuilderInterface; class DeadOrAliveFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -32,7 +41,7 @@ class DeadOrAliveFilter implements FilterInterface $where = $qb->getDQLPart('where'); $personState = $data['person_state']; - $calc = $data['date_calc']; + $calc = $this->rollingDateConverter->convert($data['date_calc']); if ('alive' === $personState) { $clause = $qb->expr()->orX( @@ -91,9 +100,9 @@ class DeadOrAliveFilter implements FilterInterface 'expanded' => true, ]); - $builder->add('date_calc', ChillDateType::class, [ + $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Filter in relation to this date', - 'data' => new DateTime('now'), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -101,7 +110,7 @@ class DeadOrAliveFilter implements FilterInterface { return ['Filtered by a state of %deadOrAlive%: ' . 'at this date %date_calc%', [ - '%date_calc%' => $data['date_calc']->format('d-m-Y'), + '%date_calc%' => $this->rollingDateConverter->convert($data['date_calc'])->format('d-m-Y'), '%deadOrAlive%' => $data['person_state'], ], ]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php index 48749006d..568995461 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php @@ -13,9 +13,10 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -23,6 +24,14 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; class DeathdateFilter implements ExportElementValidatedInterface, FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -44,8 +53,12 @@ class DeathdateFilter implements ExportElementValidatedInterface, FilterInterfac } $qb->add('where', $where); - $qb->setParameter('date_from', $data['date_from']); - $qb->setParameter('date_to', $data['date_to']); + $qb->setParameter('date_from', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('date_to', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn() @@ -55,14 +68,14 @@ class DeathdateFilter implements ExportElementValidatedInterface, FilterInterfac public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, [ + $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Death after this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); - $builder->add('date_to', ChillDateType::class, [ + $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Deathdate before', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -70,8 +83,8 @@ class DeathdateFilter implements ExportElementValidatedInterface, FilterInterfac { return ['Filtered by person\'s deathdate: ' . 'between %date_from% and %date_to%', [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), + '%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ], ]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php index 03d9ab568..e2bb0a09b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php @@ -13,13 +13,14 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; @@ -32,14 +33,18 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface private TranslatableStringHelperInterface $translatableStringHelper; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( GeographicalUnitRepositoryInterface $geographicalUnitRepository, GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, - TranslatableStringHelperInterface $translatableStringHelper + TranslatableStringHelperInterface $translatableStringHelper, + RollingDateConverterInterface $rollingDateConverter ) { $this->geographicalUnitRepository = $geographicalUnitRepository; $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -70,7 +75,9 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface ->andWhere( $qb->expr()->exists($subQuery) ) - ->setParameter('person_filter_geog_date', $data['date_calc']) + ->setParameter('person_filter_geog_date', + $this->rollingDateConverter->convert($data['date_calc']) + ) ->setParameter('person_filter_geog_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); } @@ -82,11 +89,10 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_calc', ChillDateType::class, [ + ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new DateTimeImmutable('today'), - 'input' => 'datetime_immutable', + 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', @@ -108,7 +114,7 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface return [ 'exports.by_person.Filtered by person\'s geographical unit (based on address) computed at datecalc, only units', [ - 'datecalc' => $data['date_calc']->format('Y-m-d'), + 'datecalc' => $this->rollingDateConverter->convert($data['date_calc'])->format('Y-m-d'), 'units' => implode( ', ', array_map( diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php index 632ab8d3b..2aa6e92ad 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php @@ -12,12 +12,13 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Person\ResidentialAddress; use Chill\PersonBundle\Export\Declarations; use Chill\ThirdPartyBundle\Entity\ThirdPartyCategory; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -28,9 +29,14 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface { private TranslatableStringHelper $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) - { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter, + TranslatableStringHelper $translatableStringHelper + ) { $this->translatableStringHelper = $translatableStringHelper; + $this->rollingDateConverter = $rollingDateConverter; } public function addRole(): ?string @@ -77,7 +83,9 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface } $qb->setParameter('type', $data['thirdparty_cat']); - $qb->setParameter('date', $data['date_calc']); + $qb->setParameter('date', + $this->rollingDateConverter->convert($data['date_calc']) + ); $qb->add('where', $where); } @@ -98,9 +106,9 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface 'expanded' => true, ]); - $builder->add('date_calc', ChillDateType::class, [ + $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Date during which residential address was valid', - 'data' => new DateTime('now'), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -108,7 +116,7 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface { return ['Filtered by person\'s who have a residential address located at a thirdparty of type %thirdparty_type% and valid on %date_calc%', [ '%thirdparty_type%' => $this->translatableStringHelper->localize($data['thirdparty_cat'][0]->getName()), - '%date_calc%' => $data['date_calc']->format('d-m-Y'), + '%date_calc%' => $this->rollingDateConverter->convert($data['date_calc'])->format('d-m-Y'), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php index 7408f7c2b..c92919ef3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php @@ -12,10 +12,11 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Entity\Person\ResidentialAddress; use Chill\PersonBundle\Export\Declarations; -use DateTime; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; @@ -23,6 +24,14 @@ use function in_array; class ResidentialAddressAtUserFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -57,7 +66,9 @@ class ResidentialAddressAtUserFilter implements FilterInterface $where = $qb->expr()->andX($clause); } - $qb->setParameter('date', $data['date_calc']); + $qb->setParameter('date', + $this->rollingDateConverter->convert($data['date_calc']) + ); $qb->add('where', $where); } @@ -68,9 +79,9 @@ class ResidentialAddressAtUserFilter implements FilterInterface public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_calc', ChillDateType::class, [ + $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Date during which residential address was valid', - 'data' => new DateTime('now'), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } diff --git a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php index ec4ea7fc5..a7aa19ab0 100644 --- a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php +++ b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php @@ -12,12 +12,21 @@ declare(strict_types=1); namespace Chill\ReportBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\ChillDateType; -use DateTime; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Doctrine\ORM\Query\Expr; class ReportDateFilter implements FilterInterface { + private RollingDateConverterInterface $rollingDateConverter; + + public function __construct( + RollingDateConverterInterface $rollingDateConverter + ) { + $this->rollingDateConverter = $rollingDateConverter; + } + public function addRole(): ?string { return null; @@ -39,8 +48,12 @@ class ReportDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('report_date_filter_date_from', $data['date_from']); - $qb->setParameter('report_date_filter_date_to', $data['date_to']); + $qb->setParameter('report_date_filter_date_from', + $this->rollingDateConverter->convert($data['date_from']) + ); + $qb->setParameter('report_date_filter_date_to', + $this->rollingDateConverter->convert($data['date_to']) + ); } public function applyOn() @@ -50,14 +63,14 @@ class ReportDateFilter implements FilterInterface public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, [ + $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Report is after this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); - $builder->add('date_to', ChillDateType::class, [ + $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Report is before this date', - 'data' => new DateTime(), + 'data' => new RollingDate(RollingDate::T_TODAY), ]); } @@ -65,8 +78,8 @@ class ReportDateFilter implements FilterInterface { return ['Filtered by report\'s date: ' . 'between %date_from% and %date_to%', [ - '%date_from%' => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), + '%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'), + '%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'), ], ]; } From e767557216d9749ed7adf6d54ad6da99e279d135 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 14 Nov 2022 16:03:04 +0100 Subject: [PATCH 88/99] csfixer --- .../Export/Filter/ActivityDateFilter.php | 12 +++++++----- .../src/Export/Filter/ByDateFilter.php | 12 +++++++----- .../Export/Filter/BetweenDatesFilter.php | 6 ++++-- .../GeographicalUnitStatAggregator.php | 12 +++++++----- .../ReferrerAggregator.php | 9 +++++---- .../ReferrerScopeAggregator.php | 9 +++++---- .../ChildrenNumberAggregator.php | 7 ++++--- .../HouseholdAggregators/CompositionAggregator.php | 7 ++++--- .../ByHouseholdCompositionAggregator.php | 7 ++++--- .../PersonAggregators/GeographicalUnitAggregator.php | 9 +++++---- .../HouseholdPositionAggregator.php | 7 ++++--- .../AccompanyingCourseFilters/ActiveOnDateFilter.php | 3 ++- .../ActiveOneDayBetweenDatesFilter.php | 6 ++++-- .../GeographicalUnitStatFilter.php | 11 ++++++----- .../HasNoReferrerFilter.php | 3 ++- .../HasTemporaryLocationFilter.php | 3 ++- .../AccompanyingCourseFilters/ReferrerFilter.php | 9 +++++---- .../AccompanyingCourseFilters/UserJobFilter.php | 9 +++++---- .../AccompanyingCourseFilters/UserScopeFilter.php | 9 +++++---- .../Filter/EvaluationFilters/ByEndDateFilter.php | 6 ++++-- .../Filter/EvaluationFilters/ByStartDateFilter.php | 6 ++++-- .../Filter/HouseholdFilters/CompositionFilter.php | 7 ++++--- .../Export/Filter/PersonFilters/BirthdateFilter.php | 6 ++++-- .../Export/Filter/PersonFilters/DeathdateFilter.php | 6 ++++-- .../Filter/PersonFilters/GeographicalUnitFilter.php | 11 ++++++----- .../ResidentialAddressAtThirdpartyFilter.php | 7 ++++--- .../PersonFilters/ResidentialAddressAtUserFilter.php | 3 ++- .../Export/Filter/ReportDateFilter.php | 6 ++++-- 28 files changed, 123 insertions(+), 85 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php index edfa9b030..f2216c929 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -13,10 +13,10 @@ namespace Chill\ActivityBundle\Export\Filter; use Chill\ActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\Export\FilterType; use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Form\Type\Export\FilterType; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -27,10 +27,10 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ActivityDateFilter implements FilterInterface { - private RollingDateConverterInterface $rollingDateConverter; - protected TranslatorInterface $translator; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( TranslatorInterface $translator, RollingDateConverterInterface $rollingDateConverter @@ -60,10 +60,12 @@ class ActivityDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('date_from', + $qb->setParameter( + 'date_from', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('date_to', + $qb->setParameter( + 'date_to', $this->rollingDateConverter->convert($data['date_to']) ); } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index fca4dece8..099c87fc0 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -13,10 +13,10 @@ namespace Chill\AsideActivityBundle\Export\Filter; use Chill\AsideActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Form\Type\Export\FilterType; use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Form\Type\Export\FilterType; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -27,10 +27,10 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ByDateFilter implements FilterInterface { - private RollingDateConverterInterface $rollingDateConverter; - protected TranslatorInterface $translator; + private RollingDateConverterInterface $rollingDateConverter; + public function __construct( RollingDateConverterInterface $rollingDateConverter, TranslatorInterface $translator @@ -60,10 +60,12 @@ class ByDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('date_from', + $qb->setParameter( + 'date_from', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('date_to', + $qb->setParameter( + 'date_to', $this->rollingDateConverter->convert($data['date_to']) ); } diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php index 01bfad033..9e0358609 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php @@ -50,11 +50,13 @@ class BetweenDatesFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('dateFrom', + $qb->setParameter( + 'dateFrom', $this->rollingDateConverter->convert($data['date_from']) ); // modify dateTo so that entire day is also taken into account up until the beginning of the next day. - $qb->setParameter('dateTo', + $qb->setParameter( + 'dateTo', $this->rollingDateConverter->convert($data['date_to'])->modify('+1 day') ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php index 59a39ab12..22a2cb719 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php @@ -16,9 +16,9 @@ use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; @@ -33,10 +33,10 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface { private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; - private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelperInterface $translatableStringHelper; + public function __construct( GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, TranslatableStringHelperInterface $translatableStringHelper, @@ -67,7 +67,8 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface ) ); - $qb->setParameter('acp_geog_aggregator_date', + $qb->setParameter( + 'acp_geog_aggregator_date', $this->rollingDateConverter->convert($data['date_calc']) ); } @@ -88,7 +89,8 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface ) ); - $qb->setParameter('acp_geog_aggregator_date', + $qb->setParameter( + 'acp_geog_aggregator_date', $this->rollingDateConverter->convert($data['date_calc']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php index 84da976c6..01bc3a459 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php @@ -13,9 +13,9 @@ namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\UserRepository; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\UserRepository; use Chill\MainBundle\Templating\Entity\UserRender; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -27,12 +27,12 @@ final class ReferrerAggregator implements AggregatorInterface private const P = 'acp_ref_agg_date'; + private RollingDateConverterInterface $rollingDateConverter; + private UserRender $userRender; private UserRepository $userRepository; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( UserRepository $userRepository, UserRender $userRender, @@ -66,7 +66,8 @@ final class ReferrerAggregator implements AggregatorInterface ) ) ) - ->setParameter(self::P, + ->setParameter( + self::P, $this->rollingDateConverter->convert($data['date_calc']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php index 16ff76e3d..62f8cdef2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php @@ -13,9 +13,9 @@ namespace Chill\PersonBundle\Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -26,12 +26,12 @@ class ReferrerScopeAggregator implements AggregatorInterface { private const SCOPE_KEY = 'acp_agg_refscope_user_history_ref_scope_name'; + private RollingDateConverterInterface $rollingDateConverter; + private ScopeRepositoryInterface $scopeRepository; private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( ScopeRepositoryInterface $scopeRepository, TranslatableStringHelperInterface $translatableStringHelper, @@ -69,7 +69,8 @@ class ReferrerScopeAggregator implements AggregatorInterface ) ) ) - ->setParameter($dateCalc, + ->setParameter( + $dateCalc, $this->rollingDateConverter->convert($data['date_calc']) ); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php index aa2e9b4b6..0c9bc623f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php @@ -24,10 +24,10 @@ use function in_array; class ChildrenNumberAggregator implements AggregatorInterface { - private TranslatorInterface $translator; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatorInterface $translator; + public function __construct( TranslatorInterface $translator, RollingDateConverterInterface $rollingDateConverter @@ -59,7 +59,8 @@ class ChildrenNumberAggregator implements AggregatorInterface ->addSelect('composition_children.numberOfChildren AS childrennumber_aggregator') ->addGroupBy('childrennumber_aggregator'); - $qb->setParameter('ondate_composition_children', + $qb->setParameter( + 'ondate_composition_children', $this->rollingDateConverter->convert($data['on_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php index 1917a51b3..19884dd10 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php @@ -25,12 +25,12 @@ use function in_array; class CompositionAggregator implements AggregatorInterface { + private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelper $translatableStringHelper; private HouseholdCompositionTypeRepository $typeRepository; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( HouseholdCompositionTypeRepository $typeRepository, TranslatableStringHelper $translatableStringHelper, @@ -64,7 +64,8 @@ class CompositionAggregator implements AggregatorInterface ->addSelect('IDENTITY(composition_type.householdCompositionType) AS composition_aggregator') ->addGroupBy('composition_aggregator'); - $qb->setParameter('ondate_composition_type', + $qb->setParameter( + 'ondate_composition_type', $this->rollingDateConverter->convert($data['on_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php index 576f52626..03e5f17ce 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php @@ -29,10 +29,10 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface private HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository; - private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelperInterface $translatableStringHelper; + public function __construct( RollingDateConverterInterface $rollingDateConverter, HouseholdCompositionTypeRepositoryInterface $householdCompositionTypeRepository, @@ -78,7 +78,8 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface ) ) ->addSelect("IDENTITY({$p}_compo.householdCompositionType) AS {$p}_select") - ->setParameter("{$p}_date", + ->setParameter( + "{$p}_date", $this->rollingDateConverter->convert($data['date_calc']) ) ->addGroupBy("{$p}_select"); diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php index dd6f10035..6c92be3fd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php @@ -15,9 +15,9 @@ use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\Query\Expr\Join; @@ -30,10 +30,10 @@ class GeographicalUnitAggregator implements AggregatorInterface { private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; - private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelperInterface $translatableStringHelper; + public function __construct( GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, TranslatableStringHelperInterface $translatableStringHelper, @@ -73,7 +73,8 @@ class GeographicalUnitAggregator implements AggregatorInterface $qb->expr()->in('person_geog_agg_geog_unit.layer', ':person_geog_agg_layers') ) ) - ->setParameter('person_geog_agg_date', + ->setParameter( + 'person_geog_agg_date', $this->rollingDateConverter->convert($data['date_calc']) ) ->setParameter('person_geog_agg_layers', $data['level']) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php index 0d986bdea..ea516dbb0 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php @@ -31,12 +31,12 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl { private PositionRepository $positionRepository; + private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelper $translatableStringHelper; private TranslatorInterface $translator; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, @@ -72,7 +72,8 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl ) )); - $qb->setParameter('date', + $qb->setParameter( + 'date', $this->rollingDateConverter->convert($data['date_position']) ); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php index 55fe56d59..3fa8d711f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php @@ -53,7 +53,8 @@ class ActiveOnDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('ondate', + $qb->setParameter( + 'ondate', $this->rollingDateConverter->convert($data['on_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php index 4d1a9ad23..f713e8a97 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php @@ -38,10 +38,12 @@ class ActiveOneDayBetweenDatesFilter implements FilterInterface $clause = "OVERLAPSI (acp.openingDate, acp.closingDate), (:datefrom, :dateto) = 'TRUE'"; $qb->andWhere($clause); - $qb->setParameter('datefrom', + $qb->setParameter( + 'datefrom', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('dateto', + $qb->setParameter( + 'dateto', $this->rollingDateConverter->convert($data['date_to']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php index 55e710f8e..0c445ec3b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php @@ -16,10 +16,10 @@ use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; @@ -40,10 +40,10 @@ class GeographicalUnitStatFilter implements FilterInterface private GeographicalUnitRepositoryInterface $geographicalUnitRepository; - private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelperInterface $translatableStringHelper; + public function __construct( EntityManagerInterface $em, GeographicalUnitRepositoryInterface $geographicalUnitRepository, @@ -88,7 +88,8 @@ class GeographicalUnitStatFilter implements FilterInterface $qb ->andWhere($qb->expr()->exists($subQueryDql)) - ->setParameter('acp_geog_filter_date', + ->setParameter( + 'acp_geog_filter_date', $this->rollingDateConverter->convert($data['date_calc']) ) ->setParameter('acp_geog_filter_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index ff30b6312..4c682a56a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -49,7 +49,8 @@ class HasNoReferrerFilter implements FilterInterface AND uh.accompanyingPeriod = acp ) ') - ->setParameter('has_no_referrer_filter_date', + ->setParameter( + 'has_no_referrer_filter_date', $this->rollingDateConverter->convert($data['calc_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 3dfbea9c2..7aadde734 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -42,7 +42,8 @@ class HasTemporaryLocationFilter implements FilterInterface ->join('acp.locationHistories', 'acp_having_temporarily_location') ->andWhere('acp_having_temporarily_location.startDate <= :acp_having_temporarily_location_date AND (acp_having_temporarily_location.endDate IS NULL OR acp_having_temporarily_location.endDate > :acp_having_temporarily_location_date)') - ->setParameter('acp_having_temporarily_location_date', + ->setParameter( + 'acp_having_temporarily_location_date', $this->rollingDateConverter->convert($data['calc_date']) ); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php index 5e1ad18b9..b37d90d84 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php @@ -13,9 +13,9 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\MainBundle\Templating\Entity\UserRender; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -29,10 +29,10 @@ class ReferrerFilter implements FilterInterface private const PU = 'acp_referrer_filter_users'; - private UserRender $userRender; - private RollingDateConverterInterface $rollingDateConverter; + private UserRender $userRender; + public function __construct( UserRender $userRender, RollingDateConverterInterface $rollingDateConverter @@ -63,7 +63,8 @@ class ReferrerFilter implements FilterInterface $qb->expr()->in(self::A . '.user', ':' . self::PU) ) ->setParameter(self::PU, $data['accepted_referrers']) - ->setParameter(self::P, + ->setParameter( + self::P, $this->rollingDateConverter->convert($data['date_calc']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php index fadc5d295..b97f97dda 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php @@ -15,9 +15,9 @@ use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\UserJobRepositoryInterface; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\UserJobRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -35,14 +35,14 @@ class UserJobFilter implements FilterInterface private const PJ = 'acp_ujob_filter_job'; + private RollingDateConverterInterface $rollingDateConverter; + private Security $security; private TranslatableStringHelper $translatableStringHelper; private UserJobRepositoryInterface $userJobRepository; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( Security $security, TranslatableStringHelper $translatableStringHelper, @@ -73,7 +73,8 @@ class UserJobFilter implements FilterInterface ) ) ) - ->setParameter(self::P, + ->setParameter( + self::P, $this->rollingDateConverter->convert($data['date_calc']) ) ->join(self::A . '.user', self::AU) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php index 3fcf4f87e..bbffa4bca 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php @@ -15,9 +15,9 @@ use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; -use Chill\MainBundle\Repository\ScopeRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -35,14 +35,14 @@ class UserScopeFilter implements FilterInterface private const PS = 'acp_uscope_filter_scopes'; + private RollingDateConverterInterface $rollingDateConverter; + private ScopeRepositoryInterface $scopeRepository; private Security $security; private TranslatableStringHelper $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; - public function __construct( ScopeRepositoryInterface $scopeRepository, Security $security, @@ -73,7 +73,8 @@ class UserScopeFilter implements FilterInterface ) ) ) - ->setParameter(self::P, + ->setParameter( + self::P, $this->rollingDateConverter->convert($data['date_calc']) ) ->join(self::A . '.user', self::AU) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index 5021da1bc..1f14b04ac 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -38,10 +38,12 @@ class ByEndDateFilter implements FilterInterface { $qb ->andWhere('workeval.endDate BETWEEN :work_eval_by_end_date_start_date and :work_eval_by_end_date_end_date') - ->setParameter('work_eval_by_end_date_start_date', + ->setParameter( + 'work_eval_by_end_date_start_date', $this->rollingDateConverter->convert($data['start_date']) ) - ->setParameter('work_eval_by_end_date_end_date', + ->setParameter( + 'work_eval_by_end_date_end_date', $this->rollingDateConverter->convert($data['end_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index c5c4c8899..000f3447e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -38,10 +38,12 @@ class ByStartDateFilter implements FilterInterface { $qb ->andWhere('workeval.startDate BETWEEN :work_eval_by_start_date_start_date and :work_eval_by_start_date_end_date') - ->setParameter('work_eval_by_start_date_start_date', + ->setParameter( + 'work_eval_by_start_date_start_date', $this->rollingDateConverter->convert($data['start_date']) ) - ->setParameter('work_eval_by_start_date_end_date', + ->setParameter( + 'work_eval_by_start_date_end_date', $this->rollingDateConverter->convert($data['end_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php index e9b06d6af..922702418 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php @@ -26,10 +26,10 @@ use function in_array; class CompositionFilter implements FilterInterface { - private TranslatableStringHelper $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelper $translatableStringHelper; + public function __construct( TranslatableStringHelper $translatableStringHelper, RollingDateConverterInterface $rollingDateConverter @@ -62,7 +62,8 @@ class CompositionFilter implements FilterInterface $qb->andWhere($whereClause); $qb->setParameter('compositions', $data['accepted_composition']); - $qb->setParameter('ondate_composition_type_filter', + $qb->setParameter( + 'ondate_composition_type_filter', $this->rollingDateConverter->convert($data['on_date']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php index 24883b681..7ae22ddd8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php @@ -52,10 +52,12 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac } $qb->add('where', $where); - $qb->setParameter('date_from', + $qb->setParameter( + 'date_from', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('date_to', + $qb->setParameter( + 'date_to', $this->rollingDateConverter->convert($data['date_to']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php index 568995461..0ac4b3173 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php @@ -53,10 +53,12 @@ class DeathdateFilter implements ExportElementValidatedInterface, FilterInterfac } $qb->add('where', $where); - $qb->setParameter('date_from', + $qb->setParameter( + 'date_from', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('date_to', + $qb->setParameter( + 'date_to', $this->rollingDateConverter->convert($data['date_to']) ); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php index e2bb0a09b..d641a0140 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php @@ -14,10 +14,10 @@ namespace Chill\PersonBundle\Export\Filter\PersonFilters; use Chill\MainBundle\Entity\GeographicalUnit; use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Chill\MainBundle\Form\Type\PickRollingDateType; -use Chill\MainBundle\Service\RollingDate\RollingDate; -use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress; use Chill\PersonBundle\Export\Declarations; @@ -31,10 +31,10 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface private GeographicalUnitRepositoryInterface $geographicalUnitRepository; - private TranslatableStringHelperInterface $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelperInterface $translatableStringHelper; + public function __construct( GeographicalUnitRepositoryInterface $geographicalUnitRepository, GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, @@ -75,7 +75,8 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface ->andWhere( $qb->expr()->exists($subQuery) ) - ->setParameter('person_filter_geog_date', + ->setParameter( + 'person_filter_geog_date', $this->rollingDateConverter->convert($data['date_calc']) ) ->setParameter('person_filter_geog_units', array_map(static fn (SimpleGeographicalUnitDTO $unitDTO) => $unitDTO->id, $data['units'])); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php index 2aa6e92ad..90003c6bf 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php @@ -27,10 +27,10 @@ use function in_array; class ResidentialAddressAtThirdpartyFilter implements FilterInterface { - private TranslatableStringHelper $translatableStringHelper; - private RollingDateConverterInterface $rollingDateConverter; + private TranslatableStringHelper $translatableStringHelper; + public function __construct( RollingDateConverterInterface $rollingDateConverter, TranslatableStringHelper $translatableStringHelper @@ -83,7 +83,8 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface } $qb->setParameter('type', $data['thirdparty_cat']); - $qb->setParameter('date', + $qb->setParameter( + 'date', $this->rollingDateConverter->convert($data['date_calc']) ); $qb->add('where', $where); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php index c92919ef3..bd55c5b80 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php @@ -66,7 +66,8 @@ class ResidentialAddressAtUserFilter implements FilterInterface $where = $qb->expr()->andX($clause); } - $qb->setParameter('date', + $qb->setParameter( + 'date', $this->rollingDateConverter->convert($data['date_calc']) ); $qb->add('where', $where); diff --git a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php index a7aa19ab0..79bad4f52 100644 --- a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php +++ b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php @@ -48,10 +48,12 @@ class ReportDateFilter implements FilterInterface } $qb->add('where', $where); - $qb->setParameter('report_date_filter_date_from', + $qb->setParameter( + 'report_date_filter_date_from', $this->rollingDateConverter->convert($data['date_from']) ); - $qb->setParameter('report_date_filter_date_to', + $qb->setParameter( + 'report_date_filter_date_to', $this->rollingDateConverter->convert($data['date_to']) ); } From 2db778c4a4a5e03a106b132a452e4b14eb1b86c3 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 14 Nov 2022 16:16:38 +0100 Subject: [PATCH 89/99] fix chill-bundles#25 RollingDate bad expression --- .../Export/Filter/EvaluationFilters/ByEndDateFilter.php | 2 +- .../Export/Filter/EvaluationFilters/ByStartDateFilter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index 1f14b04ac..2dd9192bd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -58,7 +58,7 @@ class ByEndDateFilter implements FilterInterface $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new RollingDate(RollingDate::T_TODAY, new DateTimeImmutable('1 year ago')), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'input' => 'datetime_immutable', ]) ->add('end_date', PickRollingDateType::class, [ diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index 000f3447e..95314708f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -58,7 +58,7 @@ class ByStartDateFilter implements FilterInterface $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new RollingDate(RollingDate::T_TODAY, new DateTimeImmutable('1 year ago')), + 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'input' => 'datetime_immutable', ]) ->add('end_date', PickRollingDateType::class, [ From 434ef075da9d3ccf8cf1903532bdc684b6ff3da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 17:06:26 +0100 Subject: [PATCH 90/99] Feature: Add geographical unit name and ref ids in list, associated to address --- .../Export/Helper/ExportAddressHelper.php | 165 +++++++++++++++++- 1 file changed, 157 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 701f9ed07..9077b501a 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -11,13 +11,16 @@ declare(strict_types=1); namespace Chill\MainBundle\Export\Helper; +use Chill\MainBundle\Entity\GeographicalUnit; +use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Repository\AddressRepository; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\Entity\AddressRender; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\QueryBuilder; use LogicException; -use Symfony\Component\PropertyAccess\PropertyAccess; -use Symfony\Component\PropertyAccess\PropertyAccessor; +use function array_key_exists; +use function count; use function in_array; use function strlen; @@ -26,9 +29,12 @@ use function strlen; */ class ExportAddressHelper { + /** + * Compute all the F_* constants. + */ public const F_ALL = self::F_ATTRIBUTES | self::F_BUILDING | self::F_COUNTRY | - self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET; + self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET | self::F_GEOGRAPHICAL_UNITS; public const F_AS_STRING = 0b00010000; @@ -38,6 +44,8 @@ class ExportAddressHelper public const F_COUNTRY = 0b00000001; + public const F_GEOGRAPHICAL_UNITS = 0b1000000000; + public const F_GEOM = 0b00100000; public const F_POSTAL_CODE = 0b00000010; @@ -52,6 +60,7 @@ class ExportAddressHelper 'string' => self::F_AS_STRING, 'geom' => self::F_GEOM, 'attributes' => self::F_ATTRIBUTES, + 'geographical_units' => self::F_GEOGRAPHICAL_UNITS, ]; private const COLUMN_MAPPING = [ @@ -62,23 +71,35 @@ class ExportAddressHelper 'string' => ['_as_string'], 'attributes' => ['isNoAddress', 'confidential', 'id'], 'geom' => ['_lat', '_lon'], + 'geographical_units' => ['_unit_names', '_unit_refs'], ]; private AddressRender $addressRender; private AddressRepository $addressRepository; - private PropertyAccessor $propertyAccess; + private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; private TranslatableStringHelperInterface $translatableStringHelper; + /** + * @var array>|null + */ + private ?array $unitNamesKeysCache = []; + + /** + * @var array>|null + */ + private ?array $unitRefsKeysCache = []; + public function __construct( + AddressRender $addressRender, AddressRepository $addressRepository, - TranslatableStringHelperInterface $translatableStringHelper, - AddressRender $addressRender + GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, + TranslatableStringHelperInterface $translatableStringHelper ) { $this->addressRepository = $addressRepository; - $this->propertyAccess = PropertyAccess::createPropertyAccessor(); + $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; $this->addressRender = $addressRender; } @@ -155,8 +176,60 @@ class ExportAddressHelper break; + case '_unit_names': + foreach ($this->generateKeysForUnitsNames($prefix) as $alias => $layer) { + $queryBuilder + ->addSelect( + sprintf( + '(SELECT AGGREGATE(u_n_%s_%s.unitName) FROM %s u_n_%s_%s WHERE u_n_%s_%s MEMBER OF %s.geographicalUnits AND u_n_%s_%s.layer = :layer_%s_%s) AS %s', + $prefix, + $layer->getId(), + GeographicalUnit::class, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $entityName, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $alias + ) + ) + ->setParameter(sprintf('layer_%s_%s', $prefix, $layer->getId()), $layer); + } + + break; + + case '_unit_refs': + foreach ($this->generateKeysForUnitsRefs($prefix) as $alias => $layer) { + $queryBuilder + ->addSelect( + sprintf( + '(SELECT AGGREGATE(u_r_%s_%s.unitRefId) FROM %s u_r_%s_%s WHERE u_r_%s_%s MEMBER OF %s.geographicalUnits AND u_r_%s_%s.layer = :layer_%s_%s) AS %s', + $prefix, + $layer->getId(), + GeographicalUnit::class, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $entityName, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $alias + ) + ) + ->setParameter(sprintf('layer_%s_%s', $prefix, $layer->getId()), $layer); + } + + break; + default: - throw new LogicException('This key is not supported: ' . $key); + throw new LogicException(sprintf('This key is not supported: %s, field %s', $key, $field)); } } } @@ -174,6 +247,13 @@ class ExportAddressHelper foreach (self::ALL as $key => $bitmask) { if (($params & $bitmask) === $bitmask) { + if ('geographical_units' === $key) { + // geographical unit generate keys dynamically, depending on layers + $prefixes = array_merge($prefixes, array_keys($this->generateKeysForUnitsNames($prefix)), array_keys($this->generateKeysForUnitsRefs($prefix))); + + continue; + } + $prefixes = array_merge( $prefixes, array_map( @@ -271,7 +351,76 @@ class ExportAddressHelper }; default: + $layerNamesKeys = array_merge($this->generateKeysForUnitsNames($prefix), $this->generateKeysForUnitsRefs($prefix)); + + if (array_key_exists($key, $layerNamesKeys)) { + return function ($value) use ($key, $layerNamesKeys) { + if ('_header' === $value) { + $header = $this->translatableStringHelper->localize($layerNamesKeys[$key]->getName()); + + if (str_contains($key, 'unit_ref')) { + $header .= ' (id)'; + } + + return $header; + } + + if (null === $value) { + return ''; + } + + $decodedValues = json_decode($value, true); + + switch (count($decodedValues)) { + case 0: + return ''; + + case 1: + return $decodedValues[0]; + + default: + return implode('|', $decodedValues); + } + }; + } + throw new LogicException('this key is not supported: ' . $sanitizedKey); } } + + /** + * @return array + */ + private function generateKeysForUnitsNames(string $prefix): array + { + if (array_key_exists($prefix, $this->unitNamesKeysCache)) { + return $this->unitNamesKeysCache[$prefix]; + } + + $keys = []; + + foreach ($this->geographicalUnitLayerRepository->findAllHavingUnits() as $layer) { + $keys[$prefix . 'unit_names_' . $layer->getId()] = $layer; + } + + return $this->unitNamesKeysCache[$prefix] = $keys; + } + + /** + * @return array + */ + private function generateKeysForUnitsRefs(string $prefix): array + { + if (array_key_exists($prefix, $this->unitRefsKeysCache)) { + return $this->unitRefsKeysCache[$prefix]; + } + + $keys = []; + + foreach ($this->geographicalUnitLayerRepository->findAllHavingUnits() as $layer) { + $keys[$prefix . 'unit_refs_' . $layer->getId()] = $layer; + } + + return $this->unitRefsKeysCache[$prefix] = $keys; + } } From a39f5479077ef20f64ea3be11a480d34471ff4a2 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 15 Nov 2022 22:01:35 +0100 Subject: [PATCH 91/99] fix flex-bloc look in exports list and saved exports --- .../Resources/public/chill/chillmain.scss | 1 + .../Resources/views/Export/layout.html.twig | 24 +++---- .../views/SavedExport/edit.html.twig | 2 + .../views/SavedExport/index.html.twig | 68 +++++++++---------- .../Resources/views/SavedExport/new.html.twig | 2 + 5 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss index 7cd3f5479..eaa11e3d6 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss @@ -524,6 +524,7 @@ div.exports-list { flex-basis: 33%; @include media-breakpoint-down(lg) { flex-basis: 50%; } @include media-breakpoint-down(sm) { flex-basis: 100%; } + div:last-child, p:last-child { margin-top: auto; } diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig index b86f617b4..873ace4ac 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/layout.html.twig @@ -52,20 +52,18 @@

{{ 'Ungrouped exports'|trans }}

{% endif %} -
+
{% for export_alias,export in grouped_exports['_'] %} - -
-
-
-

{{ export.title|trans }}

-

{{ export.description|trans }}

-

- - {{ 'Create an export'|trans }} - -

-
+ +
+
+

{{ export.title|trans }}

+

{{ export.description|trans }}

+

+ + {{ 'Create an export'|trans }} + +

diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig index 937d42201..98cfd6281 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/edit.html.twig @@ -3,6 +3,7 @@ {% block title %}{{ 'saved_export.Edit'|trans }}{% endblock %} {% block content %} +

{{ block('title') }}

{{ form_start(form) }} @@ -18,4 +19,5 @@ {{ form_end(form) }} +
{% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index 17792ecd2..50e6f5a5f 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -3,7 +3,7 @@ {% block title %}{{ 'saved_export.My saved exports'|trans }}{% endblock %} {% block content %} -
+
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }} @@ -16,26 +16,25 @@ {% for group, saveds in grouped_exports %} {% if group != '_' %}

{{ group }}

-
+
{% for s in saveds %} -
-
-
-

{{ s.saved.title }}

-

{{ s.export.title|trans }}

- -
- {{ s.saved.description|chill_markdown_to_html }} -
- -
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
- +
+
+

{{ s.export.title|trans }}

+

{{ s.saved.title }}

+ +
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
+ +
+ {{ s.saved.description|chill_markdown_to_html }} +
+ +
-
@@ -48,29 +47,26 @@

{{ 'Ungrouped exports'|trans }}

{% endif %} -
+
{% for saveds in grouped_exports['_']|default([]) %} {% for s in saveds %} -
-
-
-
-

{{ s.saved.title }}

-

{{ s.export.title|trans }}

- -
- {{ s.saved.description|chill_markdown_to_html }} -
- -
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
- -
    -
  • -
  • -
  • -
- -
+
+
+

{{ s.export.title|trans }}

+

{{ s.saved.title }}

+ +
{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
+ +
+ {{ s.saved.description|chill_markdown_to_html }} +
+ +
+
    +
  • +
  • +
  • +
diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig index 037adb0fc..317f53e42 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig @@ -3,6 +3,7 @@ {% block title %}{{ 'saved_export.New'|trans }}{% endblock %} {% block content %} +

{{ block('title') }}

{{ form_start(form) }} @@ -18,4 +19,5 @@ {{ form_end(form) }} +
{% endblock %} \ No newline at end of file From d58aad46241cdc8d0695c1848619dede66a883f5 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 15 Nov 2022 22:08:15 +0100 Subject: [PATCH 92/99] improve savedExport translation --- .../ChillMainBundle/translations/messages.fr.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 58b3e976e..fbd8da3a7 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -558,12 +558,12 @@ rolling_date: fixed_date_date: Date fixe saved_export: - Any saved export: Aucun rapport enregistré - New: Nouveau rapport enregistré - Edit: Modifier un rapport enregistré - Delete saved ?: Supprimer un rapport enregistré ? - Are you sure you want to delete this saved ?: Êtes-vous sûr·e de vouloir supprimer ce rapport ? - My saved exports: Mes rapports enregistrés - Export is deleted: Le rapport est supprimé - Saved export is saved!: Le rapport est enregistré + Any saved export: Aucun export enregistré + New: Nouvel export enregistré + Edit: Modifier un export enregistré + Delete saved ?: Supprimer un export enregistré ? + Are you sure you want to delete this saved ?: Êtes-vous sûr·e de vouloir supprimer cet export ? + My saved exports: Mes exports enregistrés + Export is deleted: L'export est supprimé + Saved export is saved!: L'export est enregistré Created on %date%: Créé le %date% \ No newline at end of file From 00bf7bf299c22a69f94c4e4c19efbd31b205a5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 15 Nov 2022 18:17:58 +0100 Subject: [PATCH 93/99] DX: fix construct of ReferrerScopeAggregator in test --- .../ReferrerScopeAggregatorTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregatorTest.php index 07ddf1376..09d5f99df 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregatorTest.php @@ -13,6 +13,8 @@ namespace Export\Aggregator\AccompanyingCourseAggregators; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Repository\ScopeRepositoryInterface; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\PersonBundle\Entity\AccompanyingPeriod; @@ -40,9 +42,13 @@ final class ReferrerScopeAggregatorTest extends AbstractAggregatorTest (new Scope())->setName(['fr' => 'scope']) ); + $dateConverter = $this->prophesize(RollingDateConverterInterface::class); + $dateConverter->convert(Argument::type(RollingDate::class))->willReturn(new DateTimeImmutable()); + return new ReferrerScopeAggregator( $scopeRepository->reveal(), - $translatableStringHelper->reveal() + $translatableStringHelper->reveal(), + $dateConverter->reveal() ); } From 15871db7fdacd27b29098ce8e9653926e8005c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 16 Nov 2022 14:56:42 +0100 Subject: [PATCH 94/99] Fixed: [saved exports] Transform null strings into blank strings, and add validation --- src/Bundle/ChillMainBundle/Entity/SavedExport.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Entity/SavedExport.php b/src/Bundle/ChillMainBundle/Entity/SavedExport.php index 3ac361e81..81ca33e72 100644 --- a/src/Bundle/ChillMainBundle/Entity/SavedExport.php +++ b/src/Bundle/ChillMainBundle/Entity/SavedExport.php @@ -18,6 +18,7 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait; use Doctrine\ORM\Mapping as ORM; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity @@ -31,6 +32,7 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="text", nullable=false, options={"default": ""}) + * @Assert\NotBlank */ private string $description = ''; @@ -53,6 +55,7 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="text", nullable=false, options={"default": ""}) + * @Assert\NotBlank */ private string $title = ''; @@ -96,9 +99,9 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface return $this->user; } - public function setDescription(string $description): SavedExport + public function setDescription(?string $description): SavedExport { - $this->description = $description; + $this->description = (string) $description; return $this; } @@ -117,9 +120,9 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function setTitle(string $title): SavedExport + public function setTitle(?string $title): SavedExport { - $this->title = $title; + $this->title = (string) $title; return $this; } From d0e1f31ec77f66b1d6991c8635ff007e0396fc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 16 Nov 2022 14:57:09 +0100 Subject: [PATCH 95/99] Fixed: [saved exports] Fix a test in list when no export ungrouped --- .../ChillMainBundle/Resources/views/SavedExport/index.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index 50e6f5a5f..fd0cda2a7 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -43,7 +43,7 @@ {% endif %} {% endfor %} - {% if grouped_exports|keys|length > 1 and grouped_exports['_']|length > 0 %} + {% if grouped_exports|keys|length > 1 and grouped_exports['_']|default([])|length > 0 %}

{{ 'Ungrouped exports'|trans }}

{% endif %} From 318d6b6d4e7dfe5df6ede6cdbe14615b33093977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 16 Nov 2022 14:57:40 +0100 Subject: [PATCH 96/99] Fixed: remaining options not linked with PickRollingDateType --- .../GeographicalUnitStatAggregator.php | 12 ++++++------ .../Filter/EvaluationFilters/ByEndDateFilter.php | 2 -- .../Filter/EvaluationFilters/ByStartDateFilter.php | 2 -- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php index 04a6ff8cd..e0606a959 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php @@ -58,9 +58,9 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface $qb->expr()->andX( 'acp_geog_agg_location_history.startDate <= :acp_geog_aggregator_date', $qb->expr()->orX( - 'acp_geog_agg_location_history.endDate IS NULL', - 'acp_geog_agg_location_history.endDate > :acp_geog_aggregator_date' - ) + 'acp_geog_agg_location_history.endDate IS NULL', + 'acp_geog_agg_location_history.endDate > :acp_geog_aggregator_date' + ) ) ); @@ -73,9 +73,9 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface 'IDENTITY(acp_geog_agg_address_person_location.person) = IDENTITY(acp_geog_agg_location_history.personLocation)', 'acp_geog_agg_address_person_location.validFrom < :acp_geog_aggregator_date', $qb->expr()->orX( - 'acp_geog_agg_address_person_location.validTo > :acp_geog_aggregator_date', - $qb->expr()->isNull('acp_geog_agg_address_person_location.validTo') - ) + 'acp_geog_agg_address_person_location.validTo > :acp_geog_aggregator_date', + $qb->expr()->isNull('acp_geog_agg_address_person_location.validTo') + ) ) ); diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index 2dd9192bd..de86604e6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -16,7 +16,6 @@ use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -59,7 +58,6 @@ class ByEndDateFilter implements FilterInterface ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), - 'input' => 'datetime_immutable', ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index 95314708f..27518599c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -16,7 +16,6 @@ use Chill\MainBundle\Form\Type\PickRollingDateType; use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\PersonBundle\Export\Declarations; -use DateTimeImmutable; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; @@ -59,7 +58,6 @@ class ByStartDateFilter implements FilterInterface ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), - 'input' => 'datetime_immutable', ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', From 15c304b1d151a0a245fc484089addc033862576b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 16 Nov 2022 22:50:04 +0100 Subject: [PATCH 97/99] Feature: [rolling date] do not show the fixed date input, unless the `fixed date` value is picked --- .../Form/Type/PickRollingDateType.php | 9 +++++- .../public/module/pick-rolling-date/index.js | 28 +++++++++++++++++++ .../Resources/views/Export/new.html.twig | 2 ++ .../Resources/views/Form/fields.html.twig | 13 +++++++++ .../ChillMainBundle/chill.webpack.config.js | 1 + .../translations/validators.fr.yml | 3 ++ 6 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillMainBundle/Resources/public/module/pick-rolling-date/index.js diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php index 2c90379f2..5b5bff6b3 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickRollingDateType.php @@ -16,6 +16,8 @@ use Chill\MainBundle\Service\RollingDate\RollingDate; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Context\ExecutionContextInterface; @@ -59,8 +61,13 @@ class PickRollingDateType extends AbstractType if (RollingDate::T_FIXED_DATE === $data->getRoll() && null === $data->getFixedDate()) { $context ->buildViolation('rolling_date.When fixed date is selected, you must provide a date') - ->atPath('roll') + ->atPath('fixedDate') ->addViolation(); } } + + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['uniqid'] = uniqid('rollingdate-'); + } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/module/pick-rolling-date/index.js b/src/Bundle/ChillMainBundle/Resources/public/module/pick-rolling-date/index.js new file mode 100644 index 000000000..2600ea40b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/module/pick-rolling-date/index.js @@ -0,0 +1,28 @@ +import {ShowHide} from 'ChillMainAssets/lib/show_hide/index'; + +document.addEventListener('DOMContentLoaded', function(_e) { + console.log('pick-rolling-date'); + document.querySelectorAll('div[data-rolling-date]').forEach( (picker) => { + const + roll_wrapper = picker.querySelector('div.roll-wrapper'), + fixed_wrapper = picker.querySelector('div.fixed-wrapper'); + + new ShowHide({ + froms: [roll_wrapper], + container: [fixed_wrapper], + test: function (elems) { + console.log('testing'); + console.log('elems', elems); + for (let el of elems) { + for (let select_roll of el.querySelectorAll('select[data-roll-picker]')) { + console.log('select_roll', select_roll); + console.log('value', select_roll.value); + return select_roll.value === 'fixed_date'; + } + } + return false; + } + }) + }); +}); + diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig index e1605a4c2..8ef4c3ad7 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new.html.twig @@ -22,6 +22,7 @@ {% block css %} {{ encore_entry_link_tags('mod_pickentity_type') }} + {{ encore_entry_link_tags('mod_pick_rolling_date') }} {% endblock %} {% block js %} @@ -30,6 +31,7 @@ {% if export_alias == 'count_social_work_actions' %} {{ encore_entry_script_tags('vue_export_action_goal_result') }} {% endif %} + {{ encore_entry_script_tags('mod_pick_rolling_date') }} {% endblock js %} {% block content %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig index 7ab8a4c85..33ffaaa0e 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig @@ -244,3 +244,16 @@
{% endblock %} + +{% block pick_rolling_date_widget %} +
+
+ {{ form_widget(form.roll, { 'attr': { 'data-roll-picker': 'data-roll-picker'}}) }} + {{ form_errors(form.roll) }} +
+
+ {{ form_widget(form.fixedDate) }} + {{ form_errors(form.fixedDate) }} +
+
+{% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/chill.webpack.config.js b/src/Bundle/ChillMainBundle/chill.webpack.config.js index 73f539739..0e4924b03 100644 --- a/src/Bundle/ChillMainBundle/chill.webpack.config.js +++ b/src/Bundle/ChillMainBundle/chill.webpack.config.js @@ -71,6 +71,7 @@ module.exports = function(encore, entries) encore.addEntry('mod_entity_workflow_pick', __dirname + '/Resources/public/module/entity-workflow-pick/index.js'); encore.addEntry('mod_wopi_link', __dirname + '/Resources/public/module/wopi-link/index.js'); encore.addEntry('mod_pick_postal_code', __dirname + '/Resources/public/module/pick-postal-code/index.js'); + encore.addEntry('mod_pick_rolling_date', __dirname + '/Resources/public/module/pick-rolling-date/index.js'); // Vue entrypoints encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js'); diff --git a/src/Bundle/ChillMainBundle/translations/validators.fr.yml b/src/Bundle/ChillMainBundle/translations/validators.fr.yml index da433ba0f..690629e44 100644 --- a/src/Bundle/ChillMainBundle/translations/validators.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/validators.fr.yml @@ -31,3 +31,6 @@ notification: workflow: You must add at least one dest user or email: Indiquez au moins un destinataire ou une adresse email + +rolling_date: + When fixed date is selected, you must provide a date: Indiquez la date fixe choisie \ No newline at end of file From 24833be6811b474e31ac8f6bca702c1a9ee98609 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 25 Nov 2022 14:15:56 +0100 Subject: [PATCH 98/99] take into account null value in formatter --- .../ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php index 4084bfb4f..6b77e5b2b 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php @@ -445,6 +445,8 @@ class SpreadSheetFormatter implements FormatterInterface $this->initializeCache($key); } + $value = null === $value ? '' : $value; + return call_user_func($this->cacheDisplayableResult[$key], $value); } From 3ebf3ae148aacdc6ab44dab20a710c98df3ad85d Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 25 Nov 2022 14:16:44 +0100 Subject: [PATCH 99/99] fix activity list export for linked with person --- .../Export/LinkedToPerson/ListActivity.php | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php index dee5dce8d..f052c5885 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php @@ -210,10 +210,20 @@ class ListActivity implements ListInterface, GroupedExportInterface $qb ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('actperson.center', 'actcenter') - ->andWhere('actcenter IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); + ->join('activity.person', 'actperson') + ->join('actperson.centerHistory', 'centerHistory'); + + $qb->where( + $qb->expr()->andX( + $qb->expr()->lte('centerHistory.startDate', 'activity.date'), + $qb->expr()->orX( + $qb->expr()->isNull('centerHistory.endDate'), + $qb->expr()->gt('centerHistory.endDate', 'activity.date') + ) + ) + ) + ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) + ->setParameter('centers', $centers); foreach ($this->fields as $f) { if (in_array($f, $data['fields'], true)) { @@ -224,17 +234,17 @@ class ListActivity implements ListInterface, GroupedExportInterface break; case 'person_firstname': - $qb->addSelect('person.firstName AS person_firstname'); + $qb->addSelect('actperson.firstName AS person_firstname'); break; case 'person_lastname': - $qb->addSelect('person.lastName AS person_lastname'); + $qb->addSelect('actperson.lastName AS person_lastname'); break; case 'person_id': - $qb->addSelect('person.id AS person_id'); + $qb->addSelect('actperson.id AS person_id'); break; @@ -251,7 +261,7 @@ class ListActivity implements ListInterface, GroupedExportInterface break; case 'type_name': - $qb->join('activity.type', 'type'); + $qb->join('activity.activityType', 'type'); $qb->addSelect('type.name AS type_name'); break; @@ -263,6 +273,11 @@ class ListActivity implements ListInterface, GroupedExportInterface break; + case 'attendee': + $qb->addSelect('IDENTITY(activity.attendee) AS attendee'); + + break; + default: $qb->addSelect(sprintf('activity.%s as %s', $f, $f));