From d5599ac6ccea39c7d2772dfa503f96b81aefb990 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 7 May 2025 09:01:26 +0200 Subject: [PATCH] Create export list of events --- .../Export/Export/ListEvents.php | 271 ++++++++++++++++++ .../config/services/export.yaml | 3 + 2 files changed, 274 insertions(+) create mode 100644 src/Bundle/ChillEventBundle/Export/Export/ListEvents.php diff --git a/src/Bundle/ChillEventBundle/Export/Export/ListEvents.php b/src/Bundle/ChillEventBundle/Export/Export/ListEvents.php new file mode 100644 index 000000000..685912191 --- /dev/null +++ b/src/Bundle/ChillEventBundle/Export/Export/ListEvents.php @@ -0,0 +1,271 @@ +filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center']; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('fields', ChoiceType::class, [ + 'multiple' => true, + 'expanded' => true, + 'choices' => array_combine($this->fields, $this->fields), + 'label' => 'Fields to include in export', + 'constraints' => [new Callback([ + 'callback' => static function ($selected, ExecutionContextInterface $context) { + if (0 === \count($selected)) { + $context->buildViolation('You must select at least one element') + ->atPath('fields') + ->addViolation(); + } + }, + ])], + ]); + + } + + public function getFormDefaultData(): array + { + return [ + 'fields' => $this->fields, + ]; + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_LIST]; + } + + public function getDescription() + { + return 'event.export.list.description.Create a list of events according to various filters.'; + } + + public function getGroup(): string + { + return 'Exports of events'; + } + + public function getLabels($key, array $values, $data) + { + switch ($key) { + case 'event_id': + return fn ($value) => '_header' === $value ? 'ID' : $value; + + case 'event_name': + return fn ($value) => '_header' === $value ? 'Name' : $value; + + case 'event_date': + return function ($value) { + if ('_header' === $value) { + return 'Date'; + } + + if ($value instanceof \DateTime) { + return $value->format('Y-m-d'); + } + + $date = \DateTime::createFromFormat('Y-m-d H:i:s', $value); + + return $date ? $date->format('Y-m-d') : $value; + }; + + case 'event_type': + return function ($value) { + if ('_header' === $value) { + return 'event type'; + } + + return $this->translatableStringHelper->localize(json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR)); + }; + + case 'event_center': + return fn ($value) => '_header' === $value ? 'Center' : $value; + + case 'event_moderator': + return fn ($value) => '_header' === $value ? 'Moderator' : $value; + + case 'event_participants_count': + return fn ($value) => '_header' === $value ? 'Participants Count' : $value; + + case 'event_location': + return fn ($value) => '_header' === $value ? 'Location' : $value; + + default: + return fn ($value) => '_header' === $value ? $key : $value; + } + } + + public function getQueryKeys($data) + { + return $data['fields']; + } + + public function getResult($query, $data) + { + return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + + public function getTitle() + { + return 'List events'; + } + + public function getType() + { + return Declarations::EVENT; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(static fn ($el) => $el['center'], $acl); + + // Throw an error if no fields are present + if (!\array_key_exists('fields', $data)) { + throw new \InvalidArgumentException('No fields have been checked.'); + } + + $qb = $this->entityManager->createQueryBuilder() + ->from(Event::class, 'event'); + + if ($this->filterStatsByCenters) { + $qb + ->andWhere('event.center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); + } + + // Add fields based on selection + foreach ($this->fields as $field) { + if (\in_array($field, $data['fields'], true)) { + switch ($field) { + case 'event_id': + $qb->addSelect('event.id AS event_id'); + break; + + case 'event_name': + $qb->addSelect('event.name AS event_name'); + break; + + case 'event_date': + $qb->addSelect('event.date AS event_date'); + break; + + case 'event_type': + if (!$qb->getDQLPart('join') || !$this->hasJoin($qb, 'event.type')) { + $qb->leftJoin('event.type', 'type'); + } + $qb->addSelect('type.name AS event_type'); + break; + + case 'event_center': + if (!$qb->getDQLPart('join') || !$this->hasJoin($qb, 'event.center')) { + $qb->leftJoin('event.center', 'center'); + } + $qb->addSelect('center.name AS event_center'); + break; + + case 'event_moderator': + if (!$qb->getDQLPart('join') || !$this->hasJoin($qb, 'event.moderator')) { + $qb->leftJoin('event.moderator', 'user'); + } + $qb->addSelect('user.username AS event_moderator'); + break; + + case 'event_participants_count': + $qb->addSelect('(SELECT COUNT(p.id) FROM Chill\EventBundle\Entity\Participation p WHERE p.event = event.id) AS event_participants_count'); + break; + + case 'event_location': + if (!$qb->getDQLPart('join') || !$this->hasJoin($qb, 'event.location')) { + $qb->leftJoin('event.location', 'location'); + } + $qb->addSelect('location.name AS event_location'); + break; + } + } + } + + + return $qb; + } + + public function requiredRole(): string + { + return EventVoter::STATS; + } + + public function supportsModifiers() + { + return [Declarations::EVENT]; + } + + /** + * Helper method to check if a join already exists in the QueryBuilder. + */ + private function hasJoin($queryBuilder, $joinPath): bool + { + $joins = $queryBuilder->getDQLPart('join'); + if (!isset($joins['event'])) { + return false; + } + + foreach ($joins['event'] as $join) { + if ($join->getJoin() === $joinPath) { + return true; + } + } + + return false; + } +} diff --git a/src/Bundle/ChillEventBundle/config/services/export.yaml b/src/Bundle/ChillEventBundle/config/services/export.yaml index 8f8399e31..529c14893 100644 --- a/src/Bundle/ChillEventBundle/config/services/export.yaml +++ b/src/Bundle/ChillEventBundle/config/services/export.yaml @@ -8,6 +8,9 @@ services: Chill\EventBundle\Export\Export\CountEvents: tags: - { name: chill.export, alias: 'count_events' } + Chill\EventBundle\Export\Export\ListEvents: + tags: + - { name: chill.export, alias: 'list_events' } Chill\EventBundle\Export\Export\CountEventParticipations: tags: - { name: chill.export, alias: 'count_event_participants' }