diff --git a/.changes/unreleased/Feature-20231107-160435.yaml b/.changes/unreleased/Feature-20231107-160435.yaml new file mode 100644 index 000000000..e7976d27e --- /dev/null +++ b/.changes/unreleased/Feature-20231107-160435.yaml @@ -0,0 +1,5 @@ +kind: Feature +body: 'Export: add a filter "filter activity by creator job"' +time: 2023-11-07T16:04:35.921093231+01:00 +custom: + Issue: "194" diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/CreatorJobFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/CreatorJobFilter.php new file mode 100644 index 000000000..4288920e9 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Export/Filter/CreatorJobFilter.php @@ -0,0 +1,116 @@ +leftJoin('activity.createdBy', "{$p}_user") + ->leftJoin( + UserJobHistory::class, + "{$p}_history", + Join::WITH, + $qb->expr()->eq("{$p}_history.user", "{$p}_user") + ) + // job_at based on activity.date + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte("{$p}_history.startDate", 'activity.date'), + $qb->expr()->orX( + $qb->expr()->isNull("{$p}_history.endDate"), + $qb->expr()->gt("{$p}_history.endDate", 'activity.date') + ) + ) + ) + ->andWhere( + $qb->expr()->in("{$p}_history.job", ":{$p}_jobs") + ) + ->setParameter( + "{$p}_jobs", + $data['jobs'], + ); + } + + public function applyOn(): string + { + return Declarations::ACTIVITY; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('jobs', EntityType::class, [ + 'choices' => $this->userJobRepository->findAllOrderedByName(), + 'class' => UserJob::class, + 'choice_label' => fn (UserJob $s) => $this->translatableStringHelper->localize( + $s->getLabel() + ).($s->isActive() ? '' : '('.$this->translator->trans('inactive').')'), + 'label' => 'export.filter.activity.by_creator_job.job_form_label', + 'multiple' => true, + 'expanded' => true, + ]); + } + + public function describeAction($data, $format = 'string'): array + { + $jobs = array_map( + fn (UserJob $job) => $this->translatableStringHelper->localize($job->getLabel()), + $data['jobs'] instanceof Collection ? $data['jobs']->toArray() : $data['jobs'] + ); + + return ['export.filter.activity.by_creator_job.Filtered activity by user job: only %jobs%', [ + '%jobs%' => implode(', ', $jobs), + ]]; + } + + public function getFormDefaultData(): array + { + return [ + 'jobs' => [], + ]; + } + + public function getTitle(): string + { + return 'export.filter.activity.by_creator_job.Filter activity by user job'; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorJobFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorJobFilterTest.php new file mode 100644 index 000000000..bbf9b830e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/CreatorJobFilterTest.php @@ -0,0 +1,75 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + $this->translatableStringHelper = self::$container->get(TranslatableStringHelperInterface::class); + $this->translator = self::$container->get(TranslatorInterface::class); + $this->userJobRepository = self::$container->get(UserJobRepositoryInterface::class); + } + + public function getFilter() + { + return new CreatorJobFilter( + $this->translatableStringHelper, + $this->translator, + $this->userJobRepository + ); + } + + public function getFormData() + { + $this->setUp(); + $jobs = $this->userJobRepository->findAll(); + + return [ + ['jobs' => $jobs], + ]; + } + + public function getQueryBuilders() + { + self::setUp(); + + return [ + $this->entityManager->createQueryBuilder() + ->select('count(activity.id)') + ->from(Activity::class, 'activity') + ->join('activity.user', 'actuser'), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 6ce5b1d72..cb269b0f4 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -115,6 +115,10 @@ services: # affect all saved exports (unless we write a migration for that) - { name: chill.export_filter, alias: 'activity_userscope_filter' } + Chill\ActivityBundle\Export\Filter\CreatorJobFilter: + tags: + - { name: chill.export_filter, alias: 'activity_creatorjob_filter' } + Chill\ActivityBundle\Export\Filter\UsersJobFilter: tags: - { name: chill.export_filter, alias: 'activity_usersjob_filter' } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 7bb62435f..56b69fe6c 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -376,7 +376,11 @@ export: date mismatch: La date de fin de la période doit être supérieure à la date du début by_creator_scope: Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange - 'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%" + 'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur de l'échange: uniquement %scopes%" + by_creator_job: + job_form_label: Métiers + Filter activity by user job: Filtrer les échanges par métier du créateur de l'échange + 'Filtered activity by user job: only %jobs%': "Filtré par service du créateur de l'échange: uniquement %jobs%" by_persons: Filter activity by persons: Filtrer les échanges par usager participant 'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%' diff --git a/src/Bundle/ChillMainBundle/Repository/UserJobRepository.php b/src/Bundle/ChillMainBundle/Repository/UserJobRepository.php index ca3c60e1c..dee7ac9d7 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserJobRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserJobRepository.php @@ -12,14 +12,15 @@ declare(strict_types=1); namespace Chill\MainBundle\Repository; use Chill\MainBundle\Entity\UserJob; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; -class UserJobRepository implements UserJobRepositoryInterface +readonly class UserJobRepository implements UserJobRepositoryInterface { - private readonly EntityRepository $repository; + private EntityRepository $repository; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, private TranslatableStringHelperInterface $translatableStringHelper) { $this->repository = $em->getRepository(UserJob::class); } @@ -42,6 +43,15 @@ class UserJobRepository implements UserJobRepositoryInterface return $this->repository->findBy(['active' => true]); } + public function findAllOrderedByName(): array + { + $jobs = $this->findAll(); + + usort($jobs, fn (UserJob $a, UserJob $b) => $this->translatableStringHelper->localize($a->getLabel()) <=> $this->translatableStringHelper->localize($b->getLabel())); + + return $jobs; + } + /** * @param mixed|null $limit * @param mixed|null $offset diff --git a/src/Bundle/ChillMainBundle/Repository/UserJobRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/UserJobRepositoryInterface.php index 3c3f16fc1..ef7488042 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserJobRepositoryInterface.php +++ b/src/Bundle/ChillMainBundle/Repository/UserJobRepositoryInterface.php @@ -28,6 +28,13 @@ interface UserJobRepositoryInterface extends ObjectRepository */ public function findAllActive(): array; + /** + * a list of UserJob ordered by name. + * + * @return array + */ + public function findAllOrderedByName(): array; + /** * @param mixed|null $limit * @param mixed|null $offset