Merge branch '235-add-date-filter-course-by-activity' into 'master'

Add dates in the filter "filter course by activity type"

Closes #235

See merge request Chill-Projet/chill-bundles!632
This commit is contained in:
Julien Fastré 2023-12-07 15:25:09 +00:00
commit dab80a84d8
5 changed files with 89 additions and 15 deletions

View File

@ -0,0 +1,5 @@
kind: Feature
body: 'Export: add dates on the filter "filter course by activity type"'
time: 2023-12-04T18:11:56.906524311+01:00
custom:
Issue: "235"

View File

@ -15,17 +15,22 @@ use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
class ActivityTypeFilter implements FilterInterface final readonly class ActivityTypeFilter implements FilterInterface
{ {
private const BASE_EXISTS = 'SELECT 1 FROM '.Activity::class.' act_type_filter_activity WHERE act_type_filter_activity.accompanyingPeriod = acp';
public function __construct( public function __construct(
private readonly ActivityTypeRepositoryInterface $activityTypeRepository, private ActivityTypeRepositoryInterface $activityTypeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper private TranslatableStringHelperInterface $translatableStringHelper,
private RollingDateConverterInterface $rollingDateConverter,
) {} ) {}
public function addRole(): ?string public function addRole(): ?string
@ -35,15 +40,28 @@ class ActivityTypeFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->andWhere( $exists = self::BASE_EXISTS;
$qb->expr()->exists(
'SELECT 1 FROM '.Activity::class.' act_type_filter_activity if (count($data['accepted_activitytypes']) > 0) {
WHERE act_type_filter_activity.activityType IN (:act_type_filter_activity_types) AND act_type_filter_activity.accompanyingPeriod = acp' $exists .= ' AND act_type_filter_activity.activityType IN (:act_type_filter_activity_types)';
)
);
$qb->setParameter('act_type_filter_activity_types', $data['accepted_activitytypes']); $qb->setParameter('act_type_filter_activity_types', $data['accepted_activitytypes']);
} }
if (null !== $data['date_after']) {
$exists .= ' AND act_type_filter_activity.date >= :act_type_filter_activity_date_after';
$qb->setParameter('act_type_filter_activity_date_after', $this->rollingDateConverter->convert($data['date_after']));
}
if (null !== $data['date_before']) {
$exists .= ' AND act_type_filter_activity.date >= :act_type_filter_activity_date_before';
$qb->setParameter('act_type_filter_activity_date_before', $this->rollingDateConverter->convert($data['date_before']));
}
if (self::BASE_EXISTS !== $exists) {
$qb->andWhere($qb->expr()->exists($exists));
}
}
public function applyOn() public function applyOn()
{ {
return Declarations::ACP_TYPE; return Declarations::ACP_TYPE;
@ -60,11 +78,27 @@ class ActivityTypeFilter implements FilterInterface
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
]); ]);
$builder->add('date_after', PickRollingDateType::class, [
'label' => 'export.filter.activity.acp_by_activity_type.activity after',
'help' => 'export.filter.activity.acp_by_activity_type.activity after help',
'required' => false,
]);
$builder->add('date_before', PickRollingDateType::class, [
'label' => 'export.filter.activity.acp_by_activity_type.activity before',
'help' => 'export.filter.activity.acp_by_activity_type.activity before help',
'required' => false,
]);
} }
public function getFormDefaultData(): array public function getFormDefaultData(): array
{ {
return []; return [
'accepted_activitytypes' => [],
'date_after' => null,
'date_before' => null,
];
} }
public function describeAction($data, $format = 'string'): array public function describeAction($data, $format = 'string'): array
@ -75,8 +109,12 @@ class ActivityTypeFilter implements FilterInterface
$types[] = $this->translatableStringHelper->localize($aty->getName()); $types[] = $this->translatableStringHelper->localize($aty->getName());
} }
return ['export.filter.activity.acp_by_activity_type.acp_containing_at_least_one_%activitytypes%', [ return ['export.filter.activity.acp_by_activity_type.acp_containing_at_least_one_activitytypes', [
'%activitytypes%' => implode(', ', $types), 'activitytypes' => implode(', ', $types),
'has_date_after' => null !== $data['date_after'] ? 1 : 0,
'date_after' => $this->rollingDateConverter->convert($data['date_after']),
'has_date_before' => null !== $data['date_before'] ? 1 : 0,
'date_before' => $this->rollingDateConverter->convert($data['date_before']),
]]; ]];
} }

View File

@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@ -55,8 +56,30 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
$data = []; $data = [];
foreach ($array as $a) { foreach ($array as $a) {
$data[] = [
'accepted_activitytypes' => [],
'date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'date_before' => new RollingDate(RollingDate::T_TODAY),
];
$data[] = [ $data[] = [
'accepted_activitytypes' => new ArrayCollection([$a]), 'accepted_activitytypes' => new ArrayCollection([$a]),
'date_after' => null,
'date_before' => null,
];
$data[] = [
'accepted_activitytypes' => [$a],
'date_after' => null,
'date_before' => null,
];
$data[] = [
'accepted_activitytypes' => [$a],
'date_after' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'date_before' => new RollingDate(RollingDate::T_TODAY),
];
$data[] = [
'accepted_activitytypes' => [],
'date_after' => null,
'date_before' => null,
]; ];
} }

View File

@ -3,7 +3,12 @@ export:
activity: activity:
course_having_activity_between_date: 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} 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}
person_between_dates:
acp_by_activity_type:
'acp_containing_at_least_one_activitytypes': >-
Parcours filtrés: uniquement ceux qui contiennent au moins un échange d'un des types suivants: {activitytypes}
{has_date_after, select, 1 {, après le {date_after, date}} other {}}
{has_date_before, select, 1 {, avant le {date_before, date}} other {}}
describe_action_with_no_subject: >- describe_action_with_no_subject: >-
Filtré par personne ayant eu un échange entre le {date_from, date} et le {date_to, date} Filtré par personne ayant eu un échange entre le {date_from, date} et le {date_to, date}
describe_action_with_subject: >- describe_action_with_subject: >-

View File

@ -379,7 +379,10 @@ export:
Receiving an activity after: Ayant reçu un échange après le Receiving an activity after: Ayant reçu un échange après le
Receiving an activity before: Ayant reçu un échange avant le Receiving an activity before: Ayant reçu un échange avant le
acp_by_activity_type: acp_by_activity_type:
'acp_containing_at_least_one_%activitytypes%': 'Parcours filtrés: uniquement ceux qui contiennent au moins un échange d''un des types suivants: %activitytypes%' 'activity after': Échanges après le
activity after help: Si laissé vide, ne sera pas pris en compte
activity before: Echanges avant le
activity before help: Si laissé vide, ne sera pas pris en compte
person_between_dates: person_between_dates:
Implied in an activity after this date: Impliqué dans un échange après cette date Implied in an activity after this date: Impliqué dans un échange après cette date
Implied in an activity before this date: Impliqué dans un échange avant cette date Implied in an activity before this date: Impliqué dans un échange avant cette date