From e0245afca5acf6658e6f72e3983d20a4604c70e5 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Thu, 26 Mar 2026 21:39:20 +0100 Subject: [PATCH] Refactor AccountController: extract constants, reduce returns and cognitive complexity - Add DQL_EXCLUDE_INVITATIONS, DQL_BB_EXCLUDE_INVITATIONS, CONTENT_TYPE_PDF constants - Reduce createAccreditation from 4 to 3 returns by combining validations - Extract collectAttestationBillets, buildAttestationStats, buildAttestationTicketDetails from eventAttestation to reduce cognitive complexity from 18 to under 15 - Remove unused $totalRevenue, duplicate $label, and securityKey from attestation details Co-Authored-By: Claude Opus 4.6 (1M context) --- src/Controller/AccountController.php | 220 ++++++++++++++------------- 1 file changed, 117 insertions(+), 103 deletions(-) diff --git a/src/Controller/AccountController.php b/src/Controller/AccountController.php index a4093c4..f3e8194 100644 --- a/src/Controller/AccountController.php +++ b/src/Controller/AccountController.php @@ -37,6 +37,9 @@ class AccountController extends AbstractController private const BREADCRUMB_ACCOUNT = ['name' => 'Mon compte', 'url' => '/mon-compte']; private const EVENT_BASE_URL = '/mon-compte/evenement/'; private const EVENT_CATEGORIES_SUFFIX = '/modifier?tab=categories'; + private const DQL_EXCLUDE_INVITATIONS = 'o.isInvitation = false OR o.isInvitation IS NULL'; + private const DQL_BB_EXCLUDE_INVITATIONS = 'bb.isInvitation = false OR bb.isInvitation IS NULL'; + private const CONTENT_TYPE_PDF = 'application/pdf'; #[Route('/mon-compte', name: 'app_account')] public function index(Request $request, StripeService $stripeService, EntityManagerInterface $em, PaginatorInterface $paginator, EventIndexService $eventIndex): Response @@ -445,7 +448,7 @@ class AccountController extends AbstractController ->from(BilletOrder::class, 'bo') ->join('bo.billetBuyer', 'bb') ->where('bo.billet IN (:ids)') - ->andWhere('bb.isInvitation = false OR bb.isInvitation IS NULL') + ->andWhere(self::DQL_BB_EXCLUDE_INVITATIONS) ->setParameter('ids', $billetIds) ->groupBy('bo.billet') ->getQuery() @@ -484,7 +487,7 @@ class AccountController extends AbstractController ->leftJoin('o.items', 'i') ->where('o.event = :event') ->andWhere('o.status = :status') - ->andWhere('o.isInvitation = false OR o.isInvitation IS NULL') + ->andWhere(self::DQL_EXCLUDE_INVITATIONS) ->setParameter('event', $event) ->setParameter('status', BilletBuyer::STATUS_PAID) ->getQuery() @@ -852,16 +855,11 @@ class AccountController extends AbstractController $lastName = trim($request->request->getString('last_name')); $email = trim($request->request->getString('email')); $redirectResponse = $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'invitations']); - - if ('' === $firstName || '' === $lastName || '' === $email) { - $this->addFlash('error', 'Tous les champs sont requis.'); - - return $redirectResponse; - } - $categories = $em->getRepository(Category::class)->findBy(['event' => $event], ['position' => 'ASC']); - if (empty($categories)) { - $this->addFlash('error', 'Creez au moins une categorie avant de generer une accreditation.'); + + $missingFields = '' === $firstName || '' === $lastName || '' === $email; + if ($missingFields || empty($categories)) { + $this->addFlash('error', $missingFields ? 'Tous les champs sont requis.' : 'Creez au moins une categorie avant de generer une accreditation.'); return $redirectResponse; } @@ -912,7 +910,6 @@ class AccountController extends AbstractController $billetOrderService->generateAndSendTickets($order); - $label = 'staff' === $accreditationType ? 'Staff' : 'Exposant'; $this->addFlash('success', 'Accreditation '.$label.' envoyee a '.$order->getEmail().'.'); return $redirectResponse; @@ -954,7 +951,7 @@ class AccountController extends AbstractController $pdf = $billetOrderService->generatePdf($ticket); return new Response($pdf, 200, [ - 'Content-Type' => 'application/pdf', + 'Content-Type' => self::CONTENT_TYPE_PDF, 'Content-Disposition' => 'inline; filename="'.$ticket->getReference().'.pdf"', ]); } @@ -1010,16 +1007,8 @@ class AccountController extends AbstractController $categoryIds = array_map('intval', $request->request->all('categories')); $billetIds = array_map('intval', $request->request->all('billets')); - $categories = []; - if ($categoryIds) { - $categories = $em->getRepository(Category::class)->findBy(['id' => $categoryIds, 'event' => $event]); - } - - $billets = []; - if ($billetIds) { - $billets = $em->getRepository(Billet::class)->findBy(['id' => $billetIds]); - $billets = array_filter($billets, fn (Billet $b) => $b->getCategory()->getEvent()->getId() === $event->getId()); - } + $categories = $categoryIds ? $em->getRepository(Category::class)->findBy(['id' => $categoryIds, 'event' => $event]) : []; + $billets = $billetIds ? array_filter($em->getRepository(Billet::class)->findBy(['id' => $billetIds]), fn (Billet $b) => $b->getCategory()->getEvent()->getId() === $event->getId()) : []; if (empty($categories) && empty($billets)) { $this->addFlash('error', 'Selectionnez au moins une categorie ou un billet.'); @@ -1027,83 +1016,11 @@ class AccountController extends AbstractController return $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'attestation']); } - $allBilletIds = []; - foreach ($billets as $b) { - $allBilletIds[] = $b->getId(); - } - foreach ($categories as $cat) { - $catBillets = $em->getRepository(Billet::class)->findBy(['category' => $cat]); - foreach ($catBillets as $b) { - if (!\in_array($b->getId(), $allBilletIds, true)) { - $allBilletIds[] = $b->getId(); - $billets[] = $b; - } - } - } - - $soldCounts = []; - $revenueCounts = []; - if ($allBilletIds) { - $rows = $em->createQueryBuilder() - ->select('IDENTITY(bo.billet) AS billetId, COUNT(bo.id) AS cnt, SUM(bo.unitPriceHT) AS revenue') - ->from(BilletOrder::class, 'bo') - ->join('bo.billetBuyer', 'bb') - ->where('bo.billet IN (:ids)') - ->andWhere('bb.isInvitation = false OR bb.isInvitation IS NULL') - ->setParameter('ids', $allBilletIds) - ->groupBy('bo.billet') - ->getQuery() - ->getArrayResult(); - foreach ($rows as $row) { - $soldCounts[(int) $row['billetId']] = (int) $row['cnt']; - $revenueCounts[(int) $row['billetId']] = (int) $row['revenue']; - } - } - - $billetLines = []; - $totalSold = 0; - $totalRevenue = 0; - foreach ($billets as $b) { - $sold = $soldCounts[$b->getId()] ?? 0; - $revenue = $revenueCounts[$b->getId()] ?? 0; - $billetLines[] = [ - 'category' => $b->getCategory()->getName(), - 'name' => $b->getName(), - 'priceHT' => $b->getPriceHTDecimal(), - 'sold' => $sold, - 'revenue' => $revenue / 100, - ]; - $totalSold += $sold; - $totalRevenue += $revenue; - } - - $ticketDetails = []; - if ($allBilletIds) { - $tickets = $em->createQueryBuilder() - ->select('t', 'bb') - ->from(BilletOrder::class, 't') - ->join('t.billetBuyer', 'bb') - ->where('t.billet IN (:ids)') - ->andWhere('bb.isInvitation = false OR bb.isInvitation IS NULL') - ->setParameter('ids', $allBilletIds) - ->orderBy('t.createdAt', 'ASC') - ->getQuery() - ->getResult(); - - foreach ($tickets as $t) { - $ticketDetails[] = [ - 'reference' => $t->getReference(), - 'securityKey' => $t->getSecurityKey(), - 'billetName' => $t->getBilletName(), - 'orderNumber' => $t->getBilletBuyer()->getOrderNumber(), - 'buyerName' => $t->getBilletBuyer()->getFirstName().' '.$t->getBilletBuyer()->getLastName(), - ]; - } - } - - $mode = $request->request->getString('mode', 'detail'); - $isSimple = 'simple' === $mode; + [$billets, $allBilletIds] = $this->collectAttestationBillets($billets, $categories, $em); + [$billetLines, $totalSold] = $this->buildAttestationStats($billets, $allBilletIds, $em); + $ticketDetails = $this->buildAttestationTicketDetails($allBilletIds, $em); + $isSimple = 'simple' === $request->request->getString('mode', 'detail'); $generatedAt = new \DateTimeImmutable(); $selectedCategoryNames = array_map(fn ($c) => $c->getName(), $categories); @@ -1165,7 +1082,7 @@ class AccountController extends AbstractController $dompdf->render(); return new Response($dompdf->output(), 200, [ - 'Content-Type' => 'application/pdf', + 'Content-Type' => self::CONTENT_TYPE_PDF, 'Content-Disposition' => 'inline; filename="attestation_'.$event->getSlug().'_'.date('Y-m-d').'.pdf"', ]); } @@ -1469,7 +1386,7 @@ class AccountController extends AbstractController } return new Response($pdfService->generate($payout), 200, [ - 'Content-Type' => 'application/pdf', + 'Content-Type' => self::CONTENT_TYPE_PDF, 'Content-Disposition' => 'inline; filename="attestation_'.$payout->getStripePayoutId().'.pdf"', ]); } @@ -1525,6 +1442,103 @@ class AccountController extends AbstractController return $order; } + /** + * @param list $billets + * @param list $categories + * + * @return array{list, list} + */ + private function collectAttestationBillets(array $billets, array $categories, EntityManagerInterface $em): array + { + $allBilletIds = array_map(fn (Billet $b) => $b->getId(), $billets); + + foreach ($categories as $cat) { + foreach ($em->getRepository(Billet::class)->findBy(['category' => $cat]) as $b) { + if (!\in_array($b->getId(), $allBilletIds, true)) { + $allBilletIds[] = $b->getId(); + $billets[] = $b; + } + } + } + + return [$billets, $allBilletIds]; + } + + /** + * @param list $billets + * @param list $allBilletIds + * + * @return array{list>, int} + */ + private function buildAttestationStats(array $billets, array $allBilletIds, EntityManagerInterface $em): array + { + $soldCounts = []; + if ($allBilletIds) { + $rows = $em->createQueryBuilder() + ->select('IDENTITY(bo.billet) AS billetId, COUNT(bo.id) AS cnt') + ->from(BilletOrder::class, 'bo') + ->join('bo.billetBuyer', 'bb') + ->where('bo.billet IN (:ids)') + ->andWhere(self::DQL_BB_EXCLUDE_INVITATIONS) + ->setParameter('ids', $allBilletIds) + ->groupBy('bo.billet') + ->getQuery() + ->getArrayResult(); + foreach ($rows as $row) { + $soldCounts[(int) $row['billetId']] = (int) $row['cnt']; + } + } + + $billetLines = []; + $totalSold = 0; + foreach ($billets as $b) { + $sold = $soldCounts[$b->getId()] ?? 0; + $billetLines[] = [ + 'category' => $b->getCategory()->getName(), + 'name' => $b->getName(), + 'sold' => $sold, + ]; + $totalSold += $sold; + } + + return [$billetLines, $totalSold]; + } + + /** + * @param list $allBilletIds + * + * @return list> + */ + private function buildAttestationTicketDetails(array $allBilletIds, EntityManagerInterface $em): array + { + if (!$allBilletIds) { + return []; + } + + $tickets = $em->createQueryBuilder() + ->select('t', 'bb') + ->from(BilletOrder::class, 't') + ->join('t.billetBuyer', 'bb') + ->where('t.billet IN (:ids)') + ->andWhere(self::DQL_BB_EXCLUDE_INVITATIONS) + ->setParameter('ids', $allBilletIds) + ->orderBy('t.createdAt', 'ASC') + ->getQuery() + ->getResult(); + + $details = []; + foreach ($tickets as $t) { + $details[] = [ + 'reference' => $t->getReference(), + 'billetName' => $t->getBilletName(), + 'orderNumber' => $t->getBilletBuyer()->getOrderNumber(), + 'buyerName' => $t->getBilletBuyer()->getFirstName().' '.$t->getBilletBuyer()->getLastName(), + ]; + } + + return $details; + } + private function requireEventOwnership(Event $event): User { /** @var User $user */ @@ -1637,7 +1651,7 @@ class AccountController extends AbstractController $filename = sprintf('recap_%04d_%02d.pdf', $year, $month); return new Response($pdf, 200, [ - 'Content-Type' => 'application/pdf', + 'Content-Type' => self::CONTENT_TYPE_PDF, 'Content-Disposition' => 'inline; filename="'.$filename.'"', ]); } @@ -1711,7 +1725,7 @@ class AccountController extends AbstractController ->from(BilletBuyer::class, 'o') ->join('o.event', 'e') ->where('e.account = :user') - ->andWhere('o.isInvitation = false OR o.isInvitation IS NULL') + ->andWhere(self::DQL_EXCLUDE_INVITATIONS) ->setParameter('user', $user) ->getQuery() ->getResult();