diff --git a/.changes/unreleased/DX-20230623-122408.yaml b/.changes/unreleased/DX-20230623-122408.yaml
deleted file mode 100644
index 58dd96180..000000000
--- a/.changes/unreleased/DX-20230623-122408.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-kind: DX
-body: '[FilterOrderHelper] add entity choice and singleCheckbox'
-time: 2023-06-23T12:24:08.133491895+02:00
-custom:
- Issue: ""
diff --git a/.changes/unreleased/Feature-20230623-122530.yaml b/.changes/unreleased/Feature-20230623-122530.yaml
deleted file mode 100644
index 922750ea8..000000000
--- a/.changes/unreleased/Feature-20230623-122530.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-kind: Feature
-body: '[activity list] add filtering for activities list'
-time: 2023-06-23T12:25:30.49643551+02:00
-custom:
- Issue: ""
diff --git a/.changes/unreleased/Feature-20230623-122702.yaml b/.changes/unreleased/Feature-20230623-122702.yaml
deleted file mode 100644
index e1d1b0e1f..000000000
--- a/.changes/unreleased/Feature-20230623-122702.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-kind: Feature
-body: '[activity list] in person context, show also the activities from the accompanying
- periods where the person participates'
-time: 2023-06-23T12:27:02.159041095+02:00
-custom:
- Issue: ""
diff --git a/.changes/unreleased/Feature-20230623-124438.yaml b/.changes/unreleased/Feature-20230623-124438.yaml
deleted file mode 100644
index bc199d3bb..000000000
--- a/.changes/unreleased/Feature-20230623-124438.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-kind: Feature
-body: '[activity list] add pagination to the list of activities'
-time: 2023-06-23T12:44:38.879098862+02:00
-custom:
- Issue: ""
diff --git a/.changes/unreleased/Feature-20230707-123609.yaml b/.changes/unreleased/Feature-20230707-123609.yaml
new file mode 100644
index 000000000..51ff94d4c
--- /dev/null
+++ b/.changes/unreleased/Feature-20230707-123609.yaml
@@ -0,0 +1,5 @@
+kind: Feature
+body: '[export] Add a list for people with their associated course'
+time: 2023-07-07T12:36:09.596469063+02:00
+custom:
+ Issue: "125"
diff --git a/.changes/unreleased/Feature-20230707-124132.yaml b/.changes/unreleased/Feature-20230707-124132.yaml
new file mode 100644
index 000000000..4ad93ad22
--- /dev/null
+++ b/.changes/unreleased/Feature-20230707-124132.yaml
@@ -0,0 +1,6 @@
+kind: Feature
+body: '[export] Add ordering by person''s lastname or course opening date in list
+ which concerns accompanying course or peoples'
+time: 2023-07-07T12:41:32.112725962+02:00
+custom:
+ Issue: ""
diff --git a/.changes/unreleased/Feature-20230711-150055.yaml b/.changes/unreleased/Feature-20230711-150055.yaml
new file mode 100644
index 000000000..ecee61b49
--- /dev/null
+++ b/.changes/unreleased/Feature-20230711-150055.yaml
@@ -0,0 +1,5 @@
+kind: Feature
+body: '[Export] allow to group activities by localisation'
+time: 2023-07-11T15:00:55.770070399+02:00
+custom:
+ Issue: "128"
diff --git a/.changes/unreleased/Feature-20230711-155929.yaml b/.changes/unreleased/Feature-20230711-155929.yaml
new file mode 100644
index 000000000..329bbb677
--- /dev/null
+++ b/.changes/unreleased/Feature-20230711-155929.yaml
@@ -0,0 +1,5 @@
+kind: Feature
+body: '[export] Add a filter "filter course having an activity between two dates"'
+time: 2023-07-11T15:59:29.065329834+02:00
+custom:
+ Issue: "129"
diff --git a/.changes/unreleased/Fixed-20230712-090514.yaml b/.changes/unreleased/Fixed-20230712-090514.yaml
new file mode 100644
index 000000000..51a8b9317
--- /dev/null
+++ b/.changes/unreleased/Fixed-20230712-090514.yaml
@@ -0,0 +1,5 @@
+kind: Fixed
+body: reimplement the visualization of all calculator results (specific to AMLI)
+time: 2023-07-12T09:05:14.416268226+02:00
+custom:
+ Issue: ""
diff --git a/.changes/unreleased/Fixed-20230713-102640.yaml b/.changes/unreleased/Fixed-20230713-102640.yaml
new file mode 100644
index 000000000..e731e5252
--- /dev/null
+++ b/.changes/unreleased/Fixed-20230713-102640.yaml
@@ -0,0 +1,6 @@
+kind: Fixed
+body: |
+ Correct bug in thirdparty API search query: simplify address joins clause for child and parent kind
+time: 2023-07-13T10:26:40.503796155+02:00
+custom:
+ Issue: "126"
diff --git a/.changie.yaml b/.changie.yaml
index 8a25ed695..cda69de65 100644
--- a/.changie.yaml
+++ b/.changie.yaml
@@ -30,6 +30,8 @@ kinds:
auto: patch
- label: DX
auto: patch
+ - label: UX
+ auto: patch
newlines:
afterChangelogHeader: 1
beforeChangelogVersion: 1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b74eea58d..1bb9a8ee3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,6 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.4.0 - 2023-07-07
-
### Feature
* ([#113](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/113)) [export] on "filter by user working" on accompanying period, add two dates to filters intervention within a period
* ([#113](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/113)) [export] Add an aggregator by user's job working on a course
diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php
index 63639c149..1e911ff08 100644
--- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php
+++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php
@@ -259,8 +259,8 @@ final class ActivityController extends AbstractController
$filterArgs = [
'my_activities' => $filter->getSingleCheckboxData('my_activities'),
- 'types' => $filter->getEntityChoiceData('activity_types'),
- 'jobs' => $filter->getEntityChoiceData('jobs'),
+ 'types' => $filter->hasEntityChoice('activity_types') ? $filter->getEntityChoiceData('activity_types') : [],
+ 'jobs' => $filter->hasEntityChoice('jobs') ? $filter->getEntityChoiceData('jobs') : [],
'before' => $filter->getDateRangeData('activity_date')['to'],
'after' => $filter->getDateRangeData('activity_date')['from'],
];
@@ -327,21 +327,28 @@ final class ActivityController extends AbstractController
$filterBuilder
->addDateRange('activity_date', 'activity.date')
- ->addSingleCheckbox('my_activities', 'activity_filter.My activities')
- ->addEntityChoice('activity_types', 'activity_filter.Types', \Chill\ActivityBundle\Entity\ActivityType::class, $types, [
- 'choice_label' => function (\Chill\ActivityBundle\Entity\ActivityType $activityType) {
- $text = match ($activityType->hasCategory()) {
- true => $this->translatableStringHelper->localize($activityType->getCategory()->getName()) . ' > ',
- false => '',
- };
+ ->addSingleCheckbox('my_activities', 'activity_filter.My activities');
- return $text . $this->translatableStringHelper->localize($activityType->getName());
- }
- ])
- ->addEntityChoice('jobs', 'activity_filter.Jobs', UserJob::class, $jobs, [
- 'choice_label' => fn (UserJob $u) => $this->translatableStringHelper->localize($u->getLabel())
- ])
- ;
+ if (1 < count($types)) {
+ $filterBuilder
+ ->addEntityChoice('activity_types', 'activity_filter.Types', \Chill\ActivityBundle\Entity\ActivityType::class, $types, [
+ 'choice_label' => function (\Chill\ActivityBundle\Entity\ActivityType $activityType) {
+ $text = match ($activityType->hasCategory()) {
+ true => $this->translatableStringHelper->localize($activityType->getCategory()->getName()) . ' > ',
+ false => '',
+ };
+
+ return $text . $this->translatableStringHelper->localize($activityType->getName());
+ }
+ ]);
+ }
+
+ if (1 < count($jobs)) {
+ $filterBuilder
+ ->addEntityChoice('jobs', 'activity_filter.Jobs', UserJob::class, $jobs, [
+ 'choice_label' => fn (UserJob $u) => $this->translatableStringHelper->localize($u->getLabel())
+ ]);
+ }
return $filterBuilder->build();
}
diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityLocationAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityLocationAggregator.php
new file mode 100644
index 000000000..9103943e4
--- /dev/null
+++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityLocationAggregator.php
@@ -0,0 +1,80 @@
+getAllAliases(), true)) {
+ $qb->leftJoin('activity.location', 'actloc');
+ }
+ $qb->addSelect(sprintf('actloc.name AS %s', self::KEY));
+ $qb->addGroupBy(self::KEY);
+ }
+
+ public function applyOn(): string
+ {
+ return Declarations::ACTIVITY;
+ }
+
+ public function buildForm(FormBuilderInterface $builder)
+ {
+ // no form required for this aggregator
+ }
+ public function getFormDefaultData(): array
+ {
+ return [];
+ }
+
+ public function getLabels($key, array $values, $data): Closure
+ {
+ return function ($value): string {
+ if ('_header' === $value) {
+ return 'export.aggregator.activity.by_location.Activity Location';
+ }
+
+ if (null === $value || '' === $value) {
+ return '';
+ }
+
+ return $value;
+ };
+ }
+
+ public function getQueryKeys($data): array
+ {
+ return [self::KEY];
+ }
+
+ public function getTitle()
+ {
+ return 'export.aggregator.activity.by_location.Title';
+ }
+}
diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/PeriodHavingActivityBetweenDatesFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/PeriodHavingActivityBetweenDatesFilter.php
new file mode 100644
index 000000000..27e012d0b
--- /dev/null
+++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/PeriodHavingActivityBetweenDatesFilter.php
@@ -0,0 +1,90 @@
+add('start_date', PickRollingDateType::class, [
+ 'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity after'
+ ])
+ ->add('end_date', PickRollingDateType::class, [
+ 'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity before'
+ ]);
+ }
+
+ public function getFormDefaultData(): array
+ {
+ return [
+ 'start_date' => new RollingDate(RollingDate::T_YEAR_CURRENT_START),
+ 'end_date' => new RollingDate(RollingDate::T_TODAY)
+ ];
+ }
+
+ public function describeAction($data, $format = 'string')
+ {
+ return [
+ 'export.filter.activity.course_having_activity_between_date.Only course having an activity between from and to',
+ [
+ 'from' => $this->rollingDateConverter->convert($data['start_date']),
+ 'to' => $this->rollingDateConverter->convert($data['end_date']),
+ ]
+ ];
+ }
+
+ public function addRole(): ?string
+ {
+ return null;
+ }
+
+ public function alterQuery(QueryBuilder $qb, $data)
+ {
+ $alias = 'act_period_having_act_betw_date_alias';
+ $from = 'act_period_having_act_betw_date_start';
+ $to = 'act_period_having_act_betw_date_end';
+
+ $qb->andWhere(
+ $qb->expr()->exists(
+ 'SELECT 1 FROM ' . Activity::class . " {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = acp"
+ )
+ );
+
+ $qb
+ ->setParameter($from, $this->rollingDateConverter->convert($data['start_date']))
+ ->setParameter($to, $this->rollingDateConverter->convert($data['end_date']));
+ }
+
+ public function applyOn()
+ {
+ return \Chill\PersonBundle\Export\Declarations::ACP_TYPE;
+ }
+}
diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml
index 09817d80e..5af2895e9 100644
--- a/src/Bundle/ChillActivityBundle/config/services/export.yaml
+++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml
@@ -135,6 +135,10 @@ services:
tags:
- { name: chill.export_filter, alias: 'accompanyingcourse_has_no_activity_filter' }
+ Chill\ActivityBundle\Export\Filter\ACPFilters\PeriodHavingActivityBetweenDatesFilter:
+ tags:
+ - { name: chill.export_filter, alias: 'period_having_activity_betw_dates_filter' }
+
## Aggregators
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator:
tags:
@@ -144,6 +148,10 @@ services:
tags:
- { name: chill.export_aggregator, alias: activity_common_type_aggregator }
+ Chill\ActivityBundle\Export\Aggregator\ActivityLocationAggregator:
+ tags:
+ - { name: chill.export_aggregator, alias: activity_common_location_aggregator }
+
chill.activity.export.user_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
tags:
diff --git a/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml
new file mode 100644
index 000000000..ab3b963ab
--- /dev/null
+++ b/src/Bundle/ChillActivityBundle/translations/messages+intl-icu.fr.yml
@@ -0,0 +1,5 @@
+export:
+ filter:
+ activity:
+ course_having_activity_between_date:
+ Only course having an activity between from and to: Seulement les parcours ayant reçu au moins un échange entre le {from, date, short} et le {to, date, short}
diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
index 3099e99b0..4ddad2292 100644
--- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml
@@ -96,9 +96,6 @@ activity_filter:
My activities: Mes échanges (où j'interviens)
Types: Par type d'échange
Jobs: Par métier impliqué
- By: Filtrer par
- Search: Chercher dans la liste
- By date: Filtrer par date
#timeline
'%user% has done an %activity_type%': '%user% a effectué un échange de type "%activity_type%"'
@@ -376,6 +373,12 @@ export:
by_usersscope:
Filter by users scope: Filtrer les échanges 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%'
+ course_having_activity_between_date:
+ Title: Filtre les parcours ayant reçu un échange entre deux dates
+ Receiving an activity after: Ayant reçu un échange après le
+ Receiving an activity before: Ayant reçu un échange avant le
+
+
aggregator:
activity:
by_sent_received:
@@ -383,6 +386,9 @@ export:
is sent: envoyé
is received: reçu
Group activity by sentreceived: Grouper les échanges par envoyé / reçu
+ by_location:
+ Activity Location: Localisation de l'échange
+ Title: Grouper les échanges par localisation de l'échange
generic_doc:
filter:
diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig
index dfa286af4..a1fee19ce 100644
--- a/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig
+++ b/src/Bundle/ChillBudgetBundle/Resources/views/Budget/_macros.html.twig
@@ -1,11 +1,12 @@
-{% macro table_elements(elements, family) %}
+{% macro table_elements(elements, type) %}
+
- {{ 'Budget element type'|trans }}
- {{ 'Amount'|trans }}
- {{ 'Validity period'|trans }}
-
+ {{ 'Budget element type'|trans }}
+ {{ 'Amount'|trans }}
+ {{ 'Validity period'|trans }}
+
@@ -38,17 +39,17 @@
{% if is_granted('CHILL_BUDGET_ELEMENT_SEE', f) %}
-
+
{% endif %}
{% if is_granted('CHILL_BUDGET_ELEMENT_UPDATE', f) %}
-
+
{% endif %}
{% if is_granted('CHILL_BUDGET_ELEMENT_DELETE', f) %}
-
+
{% endif %}
@@ -69,7 +70,7 @@
{% endmacro %}
-{% macro table_results(actualCharges, actualResources) %}
+{% macro table_results(actualCharges, actualResources, results) %}
{% set totalCharges = 0 %}
{% for c in actualCharges %}
@@ -97,6 +98,20 @@
{{ result|format_currency('EUR') }}
+ {% for result in results %}
+
+ {{ result.label }}
+
+ {% if result.type == 'currency' %}
+ {{ result.result|format_currency('EUR') }}
+ {% elseif result.type == 'percentage' %}
+ {{ result.result|round(2, 'ceil') ~ '%' }}
+ {% else %}
+ {{ result.result|round(2, 'common') }}
+ {% endif %}
+
+
+ {% endfor %}
{% endmacro %}
diff --git a/src/Bundle/ChillBudgetBundle/Resources/views/Person/index.html.twig b/src/Bundle/ChillBudgetBundle/Resources/views/Person/index.html.twig
index 18d04b889..aba564206 100644
--- a/src/Bundle/ChillBudgetBundle/Resources/views/Person/index.html.twig
+++ b/src/Bundle/ChillBudgetBundle/Resources/views/Person/index.html.twig
@@ -25,7 +25,7 @@
{{ 'Budget calculator'|trans }}
- {{ table_results(charges, resources) }}
+ {{ table_results(charges, resources, results) }}
{% if is_granted('CHILL_BUDGET_ELEMENT_CREATE', person) %}
diff --git a/src/Bundle/ChillMainBundle/Export/ExportInterface.php b/src/Bundle/ChillMainBundle/Export/ExportInterface.php
index f357a9fdb..a11a51746 100644
--- a/src/Bundle/ChillMainBundle/Export/ExportInterface.php
+++ b/src/Bundle/ChillMainBundle/Export/ExportInterface.php
@@ -97,7 +97,7 @@ interface ExportInterface extends ExportElementInterface
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
* @param mixed $data The data from the export's form (as defined in `buildForm`)
*
- * @return callable(null|string|int|float|'_header' $value): string|int|\DateTimeInterface where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
+ * @return (callable(null|string|int|float|'_header' $value): string|int|\DateTimeInterface) where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
*/
public function getLabels($key, array $values, $data);
diff --git a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php
index 4e41a1740..51d1b3974 100644
--- a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php
+++ b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php
@@ -40,7 +40,7 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType
'label' => false,
'required' => false,
'attr' => [
- 'placeholder' => 'activity_filter.Search',
+ 'placeholder' => 'filter_order.Search',
]
]);
}
@@ -48,16 +48,7 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType
$checkboxesBuilder = $builder->create('checkboxes', null, ['compound' => true]);
foreach ($helper->getCheckboxes() as $name => $c) {
- $choices = array_combine(
- array_map(static function ($c, $t) {
- if (null !== $t) {
- return $t;
- }
-
- return $c;
- }, $c['choices'], $c['trans']),
- $c['choices']
- );
+ $choices = self::buildCheckboxChoices($c['choices'], $c['trans']);
$checkboxesBuilder->add($name, ChoiceType::class, [
'choices' => $choices,
@@ -148,6 +139,20 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType
}
+ public static function buildCheckboxChoices(array $choices, array $trans = []): array
+ {
+ return array_combine(
+ array_map(static function ($c, $t) {
+ if (null !== $t) {
+ return $t;
+ }
+
+ return $c;
+ }, $choices, $trans),
+ $choices
+ );
+ }
+
public function buildView(FormView $view, FormInterface $form, array $options)
{
/** @var FilterOrderHelper $helper */
diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/scss/forms.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/scss/forms.scss
index cd81f36dc..28c597bc0 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/chill/scss/forms.scss
+++ b/src/Bundle/ChillMainBundle/Resources/public/chill/scss/forms.scss
@@ -44,13 +44,5 @@ form {
}
.chill_filter_order {
- background: $gray-100; /*
- border: 3px dashed $white;
- background: repeating-linear-gradient(
- -45deg,
- $gray-100,
- $gray-100 2px,
- $white 2px,
- $white 6px
- ); */
+ background: $gray-100;
}
\ No newline at end of file
diff --git a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig
index 9a9a11fbd..adf67b81b 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig
@@ -1,110 +1,144 @@
{{ form_start(form) }}
- {% set btnSubmit = 0 %}
-
-
- {% if form.vars.has_search_box %}
-
-
- {{ form_widget(form.q) }}
-
-
-
- {% endif %}
-
- {% if form.dateRanges is defined %}
- {% set btnSubmit = 1 %}
- {% if form.dateRanges|length > 0 %}
- {% for dateRangeName, _o in form.dateRanges %}
-
- {% if form.dateRanges[dateRangeName].vars.label is not same as(false) %}
- {{ form_label(form.dateRanges[dateRangeName])}}
- {% else %}
-
{{ 'activity_filter.By date'|trans }}
- {% endif %}
-
-
+
+{% for k,v in otherParameters %}
+
+{% endfor %}
{{ form_end(form) }}
+
diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderGetActiveFilterHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderGetActiveFilterHelper.php
new file mode 100644
index 000000000..6b204e552
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderGetActiveFilterHelper.php
@@ -0,0 +1,84 @@
+
+ */
+ public function getActiveFilters(FilterOrderHelper $filterOrderHelper): array
+ {
+ $result = [];
+
+ if ($filterOrderHelper->hasSearchBox() && '' !== $filterOrderHelper->getQueryString()) {
+ $result[] = ['label' => '', 'value' => $filterOrderHelper->getQueryString(), 'position' => FilterOrderPositionEnum::SearchBox->value, 'name' => 'q'];
+ }
+
+ foreach ($filterOrderHelper->getDateRanges() as $name => ['label' => $label]) {
+ $base = ['position' => FilterOrderPositionEnum::DateRange->value, 'name' => $name, 'label' => (string)$label];
+
+ if (null !== ($from = $filterOrderHelper->getDateRangeData($name)['from'] ?? null)) {
+ $result[] = ['value' => $this->translator->trans('filter_order.by_date.From', ['from_date' => $from]), ...$base];
+ }
+ if (null !== ($to = $filterOrderHelper->getDateRangeData($name)['to'] ?? null)) {
+ $result[] = ['value' => $this->translator->trans('filter_order.by_date.To', ['to_date' => $to]), ...$base];
+ }
+ }
+
+ foreach ($filterOrderHelper->getCheckboxes() as $name => ['choices' => $choices, 'trans' => $trans]) {
+ $translatedChoice = array_combine($choices, [...$trans]);
+ foreach ($filterOrderHelper->getCheckboxData($name) as $keyChoice) {
+ $result[] = ['value' => $this->translator->trans($translatedChoice[$keyChoice]), 'label' => '', 'position' => FilterOrderPositionEnum::Checkboxes->value, 'name' => $name];
+ }
+ }
+
+ foreach ($filterOrderHelper->getEntityChoices() as $name => ['label' => $label, 'class' => $class, 'choices' => $choices, 'options' => $options]) {
+ foreach ($filterOrderHelper->getEntityChoiceData($name) as $selected) {
+ if (is_callable($options['choice_label'])) {
+ $value = call_user_func($options['choice_label'], $selected);
+ } elseif ($options['choice_label'] instanceof PropertyPathInterface || is_string($options['choice_label'])) {
+ $value = $this->propertyAccessor->getValue($selected, $options['choice_label']);
+ } else {
+ if (!$selected instanceof \Stringable) {
+ throw new \UnexpectedValueException(sprintf("we are not able to transform the value of %s to a string. Implements \\Stringable or add a 'choice_label' option to the filterFormBuilder", get_class($selected)));
+ }
+
+ $value = (string)$selected;
+ }
+
+ $result[] = ['value' => $this->translator->trans($value), 'label' => $label, 'position' => FilterOrderPositionEnum::EntityChoice->value, 'name' => $name];
+ }
+ }
+
+ foreach ($filterOrderHelper->getSingleCheckbox() as $name => ['label' => $label]) {
+ if (true === $filterOrderHelper->getSingleCheckboxData($name)) {
+ $result[] = ['label' => '', 'value' => $this->translator->trans($label), 'position' => FilterOrderPositionEnum::SingleCheckbox->value, 'name' => $name];
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php
index 8554b4431..801b700a8 100644
--- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php
+++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php
@@ -19,10 +19,15 @@ use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\PropertyAccess\PropertyAccessor;
+use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
+use Symfony\Component\PropertyAccess\PropertyPath;
+use Symfony\Component\PropertyAccess\PropertyPathInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge;
use function count;
-class FilterOrderHelper
+final class FilterOrderHelper
{
private array $checkboxes = [];
@@ -33,16 +38,12 @@ class FilterOrderHelper
private array $dateRanges = [];
- private FormFactoryInterface $formFactory;
-
public const FORM_NAME = 'f';
private array $formOptions = [];
private string $formType = FilterOrderType::class;
- private RequestStack $requestStack;
-
private ?array $searchBoxFields = null;
private ?array $submitted = null;
@@ -52,17 +53,16 @@ class FilterOrderHelper
*/
private array $entityChoices = [];
+
/**
* @var array
*/
private array $userPickers = [];
public function __construct(
- FormFactoryInterface $formFactory,
- RequestStack $requestStack
+ private readonly FormFactoryInterface $formFactory,
+ private readonly RequestStack $requestStack,
) {
- $this->formFactory = $formFactory;
- $this->requestStack = $requestStack;
}
public function addSingleCheckbox(string $name, string $label): self
@@ -97,14 +97,14 @@ class FilterOrderHelper
public function addCheckbox(string $name, array $choices, ?array $default = [], ?array $trans = [], array $options = []): self
{
- $missing = count($choices) - count($trans) - 1;
+ if ([] === $trans) {
+ $trans = $choices;
+ }
+
$this->checkboxes[$name] = [
- 'choices' => $choices, 'default' => $default,
- 'trans' => array_merge(
- $trans,
- 0 < $missing ?
- array_fill(0, $missing, null) : []
- ),
+ 'choices' => $choices,
+ 'default' => $default,
+ 'trans' => $trans,
...$options,
];
@@ -139,16 +139,31 @@ class FilterOrderHelper
return $this->getFormData()['user_pickers'][$name];
}
+ public function hasCheckboxData(string $name): bool
+ {
+ return array_key_exists($name, $this->checkboxes);
+ }
+
public function getCheckboxData(string $name): array
{
return $this->getFormData()['checkboxes'][$name];
}
+ public function hasSingleCheckboxData(string $name): bool
+ {
+ return array_key_exists($name, $this->singleCheckbox);
+ }
+
public function getSingleCheckboxData(string $name): ?bool
{
return $this->getFormData()['single_checkboxes'][$name];
}
+ public function hasEntityChoice(string $name): bool
+ {
+ return array_key_exists($name, $this->entityChoices);
+ }
+
public function getEntityChoiceData($name): mixed
{
return $this->getFormData()['entity_choices'][$name];
@@ -172,6 +187,11 @@ class FilterOrderHelper
return $this->singleCheckbox;
}
+ public function hasDateRangeData(string $name): bool
+ {
+ return array_key_exists($name, $this->dateRanges);
+ }
+
/**
* @return array{to: ?DateTimeImmutable, from: ?DateTimeImmutable}
*/
@@ -238,7 +258,6 @@ class FilterOrderHelper
}
return $r;
-
}
private function getFormData(): array
diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php
index d9a505dee..56c73871c 100644
--- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php
+++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php
@@ -14,6 +14,8 @@ namespace Chill\MainBundle\Templating\Listing;
use DateTimeImmutable;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
class FilterOrderHelperBuilder
{
@@ -44,7 +46,7 @@ class FilterOrderHelperBuilder
public function __construct(
FormFactoryInterface $formFactory,
- RequestStack $requestStack
+ RequestStack $requestStack,
) {
$this->formFactory = $formFactory;
$this->requestStack = $requestStack;
@@ -99,7 +101,7 @@ class FilterOrderHelperBuilder
{
$helper = new FilterOrderHelper(
$this->formFactory,
- $this->requestStack
+ $this->requestStack,
);
$helper->setSearchBox($this->searchBoxFields);
diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php
index c88c71af5..6665750dd 100644
--- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php
+++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php
@@ -13,6 +13,8 @@ namespace Chill\MainBundle\Templating\Listing;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
class FilterOrderHelperFactory implements FilterOrderHelperFactoryInterface
{
@@ -22,7 +24,7 @@ class FilterOrderHelperFactory implements FilterOrderHelperFactoryInterface
public function __construct(
FormFactoryInterface $formFactory,
- RequestStack $requestStack
+ RequestStack $requestStack,
) {
$this->formFactory = $formFactory;
$this->requestStack = $requestStack;
diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderPositionEnum.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderPositionEnum.php
new file mode 100644
index 000000000..09e8d39aa
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderPositionEnum.php
@@ -0,0 +1,21 @@
+render($template, [
'helper' => $helper,
+ 'active' => $this->filterOrderGetActiveFilterHelper->getActiveFilters($helper),
'form' => $helper->buildForm()->createView(),
'options' => $options,
'otherParameters' => $otherParameters,
diff --git a/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml
index 263a57049..96b2edd98 100644
--- a/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml
+++ b/src/Bundle/ChillMainBundle/translations/messages+intl-icu.fr.yaml
@@ -54,3 +54,12 @@ duration:
few {# minutes}
other {# minutes}
}
+
+filter_order:
+ by_date:
+ From: Depuis le {from_date, date, long}
+ To: Jusqu'au {to_date, date, long}
+ By: Filtrer par
+ Search: Chercher dans la liste
+ By date: Filtrer par date
+ search_box: Filtrer par contenu
diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php
index af66ab312..ab9c0db2f 100644
--- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php
+++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php
@@ -29,6 +29,7 @@ use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Export\Declarations;
+use Chill\PersonBundle\Export\Helper\ListAccompanyingPeriodHelper;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
@@ -45,95 +46,13 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function strlen;
-class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
+final readonly class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
{
- private const FIELDS = [
- 'id',
- 'step',
- 'stepSince',
- 'openingDate',
- 'closingDate',
- 'referrer',
- 'referrerSince',
- 'administrativeLocation',
- 'locationIsPerson',
- 'locationIsTemp',
- 'locationPersonName',
- 'locationPersonId',
- 'origin',
- 'closingMotive',
- 'confidential',
- 'emergency',
- 'intensity',
- 'job',
- 'isRequestorPerson',
- 'isRequestorThirdParty',
- 'requestorPerson',
- 'requestorPersonId',
- 'requestorThirdParty',
- 'requestorThirdPartyId',
- 'scopes',
- 'socialIssues',
- 'createdAt',
- 'createdBy',
- 'updatedAt',
- 'updatedBy',
- ];
-
- private ExportAddressHelper $addressHelper;
-
- private DateTimeHelper $dateTimeHelper;
-
- private EntityManagerInterface $entityManager;
-
- private PersonRenderInterface $personRender;
-
- private PersonRepository $personRepository;
-
- private RollingDateConverterInterface $rollingDateConverter;
-
- private SocialIssueRender $socialIssueRender;
-
- private SocialIssueRepository $socialIssueRepository;
-
- private ThirdPartyRender $thirdPartyRender;
-
- private ThirdPartyRepository $thirdPartyRepository;
-
- private TranslatableStringHelperInterface $translatableStringHelper;
-
- private TranslatorInterface $translator;
-
- private UserHelper $userHelper;
-
public function __construct(
- ExportAddressHelper $addressHelper,
- DateTimeHelper $dateTimeHelper,
- EntityManagerInterface $entityManager,
- PersonRenderInterface $personRender,
- PersonRepository $personRepository,
- ThirdPartyRepository $thirdPartyRepository,
- ThirdPartyRender $thirdPartyRender,
- SocialIssueRepository $socialIssueRepository,
- SocialIssueRender $socialIssueRender,
- TranslatableStringHelperInterface $translatableStringHelper,
- TranslatorInterface $translator,
- RollingDateConverterInterface $rollingDateConverter,
- UserHelper $userHelper
+ private EntityManagerInterface $entityManager,
+ private RollingDateConverterInterface $rollingDateConverter,
+ private ListAccompanyingPeriodHelper $listAccompanyingPeriodHelper,
) {
- $this->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->translator = $translator;
- $this->rollingDateConverter = $rollingDateConverter;
- $this->userHelper = $userHelper;
}
public function buildForm(FormBuilderInterface $builder)
@@ -169,141 +88,12 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
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, 512, JSON_THROW_ON_ERROR));
- };
-
- 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, 512, JSON_THROW_ON_ERROR)
- )
- );
- };
-
- 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, 512, JSON_THROW_ON_ERROR)
- )
- );
- };
-
- case 'step':
- return fn ($value) => match ($value) {
- '_header' => 'export.list.acp.step',
- null => '',
- AccompanyingPeriod::STEP_DRAFT => $this->translator->trans('course.draft'),
- AccompanyingPeriod::STEP_CONFIRMED => $this->translator->trans('course.confirmed'),
- AccompanyingPeriod::STEP_CLOSED => $this->translator->trans('course.closed'),
- AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT => $this->translator->trans('course.inactive_short'),
- AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG => $this->translator->trans('course.inactive_long'),
- default => $value,
- };
-
- case 'intensity':
- return fn ($value) => match ($value) {
- '_header' => 'export.list.acp.intensity',
- null => '',
- AccompanyingPeriod::INTENSITY_OCCASIONAL => $this->translator->trans('occasional'),
- AccompanyingPeriod::INTENSITY_REGULAR => $this->translator->trans('regular'),
- default => $value,
- };
-
- default:
- return static function ($value) use ($key) {
- if ('_header' === $value) {
- return 'export.list.acp.' . $key;
- }
-
- if (null === $value) {
- return '';
- }
-
- return $value;
- };
- }
+ return $this->listAccompanyingPeriodHelper->getLabels($key, $values, $data);
}
public function getQueryKeys($data)
{
- return array_merge(
- self::FIELDS,
- $this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields')
- );
+ return $this->listAccompanyingPeriodHelper->getQueryKeys($data);
}
public function getResult($query, $data)
@@ -341,7 +131,12 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
->setParameter('list_acp_step', AccompanyingPeriod::STEP_DRAFT)
->setParameter('authorized_centers', $centers);
- $this->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date']));
+ $this->listAccompanyingPeriodHelper->addSelectClauses($qb, $this->rollingDateConverter->convert($data['calc_date']));
+
+ $qb
+ ->addOrderBy('acp.openingDate')
+ ->addOrderBy('acp.closingDate')
+ ->addOrderBy('acp.id');
return $qb;
}
@@ -357,91 +152,4 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface
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 AND (personAddress.validFrom <= :calcDate AND (personAddress.validTo IS NULL OR 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/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php
similarity index 95%
rename from src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php
rename to src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php
index 370046232..408d0b3af 100644
--- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php
+++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonHavingAccompanyingPeriod.php
@@ -35,7 +35,12 @@ use function count;
use function in_array;
use function strlen;
-class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface
+/**
+ * List the persons, having an accompanying period.
+ *
+ * Details of the accompanying period are not included
+ */
+class ListPersonHavingAccompanyingPeriod implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface
{
private ExportAddressHelper $addressHelper;
@@ -185,6 +190,11 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac
$this->listPersonHelper->addSelect($qb, $fields, $data['address_date']);
+ $qb
+ ->addOrderBy('person.lastName')
+ ->addOrderBy('person.firstName')
+ ->addOrderBy('person.id');
+
return $qb;
}
diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php
new file mode 100644
index 000000000..ddb16bb2d
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriodDetails.php
@@ -0,0 +1,155 @@
+add('address_date', PickRollingDateType::class, [
+ 'label' => 'Data valid at this date',
+ 'help' => 'Data regarding center, addresses, and so on will be computed at this date',
+ ]);
+ }
+ public function getFormDefaultData(): array
+ {
+ return ['address_date' => new RollingDate(RollingDate::T_TODAY)];
+ }
+
+ 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 with details of period, according to various filters.';
+ }
+
+ public function getGroup(): string
+ {
+ return 'Exports of persons';
+ }
+
+ public function getLabels($key, array $values, $data)
+ {
+ if (in_array($key, $this->listPersonHelper->getAllKeys(), true)) {
+ return $this->listPersonHelper->getLabels($key, $values, $data);
+ }
+
+ return $this->listAccompanyingPeriodHelper->getLabels($key, $values, $data);
+ }
+
+ public function getQueryKeys($data)
+ {
+ return array_merge(
+ $this->listPersonHelper->getAllKeys(),
+ $this->listAccompanyingPeriodHelper->getQueryKeys($data),
+ );
+ }
+
+ 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 with period details';
+ }
+
+ 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 fn ($el) => $el['center'], $acl);
+
+ $qb = $this->entityManager->createQueryBuilder();
+
+ $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)'
+ )
+ )->setParameter('authorized_centers', $centers);
+
+ $this->listPersonHelper->addSelect($qb, ListPersonHelper::FIELDS, $this->rollingDateConverter->convert($data['address_date']));
+ $this->listAccompanyingPeriodHelper->addSelectClauses($qb, $this->rollingDateConverter->convert($data['address_date']));
+
+ $qb
+ ->addOrderBy('person.lastName')
+ ->addOrderBy('person.firstName')
+ ->addOrderBy('person.id')
+ ->addOrderBy('acp.id');
+
+ return $qb;
+ }
+
+ public function requiredRole(): string
+ {
+ return PersonVoter::LISTS;
+ }
+
+ public function supportsModifiers()
+ {
+ return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN, Declarations::ACP_TYPE];
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Export/Helper/ListAccompanyingPeriodHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/ListAccompanyingPeriodHelper.php
new file mode 100644
index 000000000..5fa2252cd
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Export/Helper/ListAccompanyingPeriodHelper.php
@@ -0,0 +1,317 @@
+addressHelper->getKeys(ExportAddressHelper::F_ALL, 'acp_address_fields')
+ );
+ }
+
+ public function getLabels($key, array $values, $data)
+ {
+ if (str_starts_with($key, 'acp_address_fields')) {
+ return $this->addressHelper->getLabel($key, $values, $data, 'acp_address_fields');
+ }
+
+ switch ($key) {
+ case 'stepSince':
+ case 'openingDate':
+ case 'closingDate':
+ case 'referrerSince':
+ case 'acpCreatedAt':
+ case 'acpUpdatedAt':
+ 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, 512, JSON_THROW_ON_ERROR));
+ };
+
+ 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, 512, JSON_THROW_ON_ERROR)
+ )
+ );
+ };
+
+ 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, 512, JSON_THROW_ON_ERROR)
+ )
+ );
+ };
+
+ case 'step':
+ return fn ($value) => match ($value) {
+ '_header' => 'export.list.acp.step',
+ null => '',
+ AccompanyingPeriod::STEP_DRAFT => $this->translator->trans('course.draft'),
+ AccompanyingPeriod::STEP_CONFIRMED => $this->translator->trans('course.confirmed'),
+ AccompanyingPeriod::STEP_CLOSED => $this->translator->trans('course.closed'),
+ AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_SHORT => $this->translator->trans('course.inactive_short'),
+ AccompanyingPeriod::STEP_CONFIRMED_INACTIVE_LONG => $this->translator->trans('course.inactive_long'),
+ default => $value,
+ };
+
+ case 'intensity':
+ return fn ($value) => match ($value) {
+ '_header' => 'export.list.acp.intensity',
+ null => '',
+ AccompanyingPeriod::INTENSITY_OCCASIONAL => $this->translator->trans('occasional'),
+ AccompanyingPeriod::INTENSITY_REGULAR => $this->translator->trans('regular'),
+ default => $value,
+ };
+
+ default:
+ return static function ($value) use ($key) {
+ if ('_header' === $value) {
+ return 'export.list.acp.' . $key;
+ }
+
+ if (null === $value) {
+ return '';
+ }
+
+ return $value;
+ };
+ }
+ }
+
+ public function addSelectClauses(QueryBuilder $qb, \DateTimeImmutable $calcDate): void
+ {
+ $qb->addSelect('acp.id AS acpId');
+ $qb->addSelect('acp.createdAt AS acpCreatedAt');
+ $qb->addSelect('acp.updatedAt AS acpUpdatedAt');
+
+ // add the regular fields
+ foreach (['openingDate', 'closingDate', 'confidential', 'emergency', 'intensity'] as $field) {
+ $qb->addSelect(sprintf('acp.%s AS %s', $field, $field));
+ }
+
+ // add the field which are simple association
+ $qb
+ ->leftJoin('acp.createdBy', "acp_created_by_t")
+ ->addSelect('acp_created_by_t.label AS acpCreatedBy');
+ $qb
+ ->leftJoin('acp.updatedBy', "acp_updated_by_t")
+ ->addSelect('acp_updated_by_t.label AS acpUpdatedBy');
+
+ foreach (['origin' => 'label', 'closingMotive' => 'name', 'job' => '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,
+ 'acpPersonAddress',
+ Join::WITH,
+ 'locationHistory.personLocation = acpPersonAddress.person AND (acpPersonAddress.validFrom <= :calcDate AND (acpPersonAddress.validTo IS NULL OR acpPersonAddress.validTo > :calcDate))'
+ )
+ ->leftJoin(Address::class, 'acp_address', Join::WITH, 'COALESCE(IDENTITY(locationHistory.addressLocation), IDENTITY(acpPersonAddress.address)) = acp_address.id');
+
+ $this->addressHelper->addSelectClauses(ExportAddressHelper::F_ALL, $qb, 'acp_address', 'acp_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/Helper/ListPersonHelper.php b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php
index 77a1d9c86..198794326 100644
--- a/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php
+++ b/src/Bundle/ChillPersonBundle/Export/Helper/ListPersonHelper.php
@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Helper;
+use Chill\MainBundle\Entity\Language;
use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\CivilityRepositoryInterface;
@@ -42,7 +43,7 @@ use function strlen;
class ListPersonHelper
{
public const FIELDS = [
- 'id',
+ 'personId',
'civility',
'firstName',
'lastName',
@@ -114,7 +115,26 @@ class ListPersonHelper
}
/**
- * @param array|value-of[] $fields
+ * Those keys are the "direct" keys, which are created when we decide to use to list all the keys.
+ *
+ * This method must be used in `getKeys` instead of the `self::FIELDS`
+ *
+ * @return array
+ */
+ public function getAllKeys(): array
+ {
+ return [
+ ...array_filter(
+ ListPersonHelper::FIELDS,
+ fn (string $key) => !in_array($key, ['address_fields', 'lifecycleUpdate'], true)
+ ),
+ ...$this->addressHelper->getKeys(ExportAddressHelper::F_ALL, 'address_fields'),
+ ...['createdAt', 'createdBy', 'updatedAt', 'updatedBy'],
+ ];
+ }
+
+ /**
+ * @param array> $fields
*/
public function addSelect(QueryBuilder $qb, array $fields, DateTimeImmutable $computedDate): void
{
@@ -124,6 +144,11 @@ class ListPersonHelper
}
switch ($f) {
+ case 'personId':
+ $qb->addSelect('person.id AS personId');
+
+ break;
+
case 'countryOfBirth':
case 'nationality':
$qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f));
@@ -138,25 +163,7 @@ class ListPersonHelper
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')
- ->addGroupBy('address_fieldscountry_t.id')
- ->addGroupBy('address_fieldspostcode_t.id');
- }
-
- if (in_array('household_id', $fields, true)) {
- $qb->addGroupBy('household_id');
- }
+ $qb->addSelect('(SELECT AGGREGATE(language.id) FROM ' . Language::class . ' language WHERE language MEMBER OF person.spokenLanguages) AS spokenLanguages');
break;
diff --git a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml
index 64360aee9..43f5556cf 100644
--- a/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml
+++ b/src/Bundle/ChillPersonBundle/config/services/exports_person.yaml
@@ -4,35 +4,27 @@ services:
autowire: true
## Indicators
- chill.person.export.count_person:
- class: Chill\PersonBundle\Export\Export\CountPerson
- autowire: true
- autoconfigure: true
+ Chill\PersonBundle\Export\Export\CountPerson:
tags:
- { name: chill.export, alias: count_person }
- chill.person.export.count_person_with_accompanying_course:
- class: Chill\PersonBundle\Export\Export\CountPersonWithAccompanyingCourse
- autowire: true
- autoconfigure: true
+ Chill\PersonBundle\Export\Export\CountPersonWithAccompanyingCourse:
tags:
- { name: chill.export, alias: count_person_with_accompanying_course }
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
+ Chill\PersonBundle\Export\Export\ListPersonHavingAccompanyingPeriod:
tags:
- { name: chill.export, alias: list_person_with_acp }
+ Chill\PersonBundle\Export\Export\ListPersonWithAccompanyingPeriodDetails:
+ tags:
+ - { name: chill.export, alias: list_person_with_acp_details }
+
Chill\PersonBundle\Export\Export\ListAccompanyingPeriod:
- autowire: true
- autoconfigure: true
tags:
- { name: chill.export, alias: list_acp }
diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
index 1dbba76d9..809d082b4 100644
--- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml
@@ -998,6 +998,8 @@ notification:
Notify referrer: Notifier le référent
Notify any: Notifier d'autres utilisateurs
+personId: Identifiant de l'usager
+
export:
export:
acp_stats:
@@ -1147,13 +1149,15 @@ export:
list:
person_with_acp:
List peoples having an accompanying period: Liste des usagers ayant un parcours d'accompagnement
+ List peoples having an accompanying period with period details: Liste des usagers concernés avec détail de chaque parcours
Create a list of people having an accompaying periods, according to various filters.: Génère une liste des usagers ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager
+ Create a list of people having an accompaying periods with details of period, according to various filters.: Génère une liste des usagers ayant un parcours d'accompagnement, selon différents critères liés au parcours ou à l'usager. Ajoute les détails du parcours à la liste.
acp:
List of accompanying periods: Liste des parcours d'accompagnements
Generate a list of accompanying periods, filtered on different parameters.: Génère une liste des parcours 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
+ acpId: Identifiant du parcours
openingDate: Date d'ouverture du parcours
closingDate: Date de fermeture du parcours
closingMotive: Motif de cloture
@@ -1161,14 +1165,14 @@ export:
confidential: Confidentiel
emergency: Urgent
intensity: Intensité
- createdAt: Créé le
- updatedAt: Dernière mise à jour le
+ acpCreatedAt: Créé le
+ acpUpdatedAt: Dernière mise à jour le
acpOrigin: Origine du parcours
origin: Origine du parcours
acpClosingMotive: Motif de fermeture
acpJob: Métier du parcours
- createdBy: Créé par
- updatedBy: Dernière modification par
+ acpCreatedBy: Créé par
+ acpUpdatedBy: Dernière modification par
administrativeLocation: Location administrative
step: Etape
stepSince: Dernière modification de l'étape
@@ -1176,7 +1180,7 @@ export:
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é
+ locationPersonName: 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 ?
diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
index 86c0fa9db..1d4e12074 100644
--- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
+++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
@@ -71,12 +71,9 @@ class ThirdPartyApiSearch implements SearchApiInterface
->setSelectKey('tparty')
->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)")
->setFromClause('chill_3party.third_party AS tparty
- LEFT JOIN chill_main_address cma ON cma.id = tparty.address_id
- LEFT JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id
LEFT JOIN chill_3party.third_party AS parent ON tparty.parent_id = parent.id
- LEFT JOIN chill_main_address cma_p ON parent.address_id = cma_p.id
- LEFT JOIN chill_main_postal_code cmpc_p ON cma_p.postcode_id = cmpc.id')
- ->andWhereClause('tparty.active IS TRUE');
+ LEFT JOIN chill_main_address cma ON cma.id = COALESCE(parent.address_id, tparty.address_id)
+ LEFT JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id');
$strs = explode(' ', $pattern);
$wheres = [];
@@ -102,9 +99,8 @@ class ThirdPartyApiSearch implements SearchApiInterface
(parent.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int
) + " .
// take postcode label into account, but lower than the canonicalized field
- "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0) + " .
- "COALESCE((LOWER(UNACCENT(cmpc_p.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)";
- $pertinenceArgs[] = [$str, $str, $str, $str, $str, $str];
+ "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)";
+ $pertinenceArgs[] = [$str, $str, $str, $str, $str];
}
}