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) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-26 21:39:20 +01:00
parent 02cce5608c
commit e0245afca5

View File

@@ -37,6 +37,9 @@ class AccountController extends AbstractController
private const BREADCRUMB_ACCOUNT = ['name' => 'Mon compte', 'url' => '/mon-compte']; private const BREADCRUMB_ACCOUNT = ['name' => 'Mon compte', 'url' => '/mon-compte'];
private const EVENT_BASE_URL = '/mon-compte/evenement/'; private const EVENT_BASE_URL = '/mon-compte/evenement/';
private const EVENT_CATEGORIES_SUFFIX = '/modifier?tab=categories'; 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')] #[Route('/mon-compte', name: 'app_account')]
public function index(Request $request, StripeService $stripeService, EntityManagerInterface $em, PaginatorInterface $paginator, EventIndexService $eventIndex): Response 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') ->from(BilletOrder::class, 'bo')
->join('bo.billetBuyer', 'bb') ->join('bo.billetBuyer', 'bb')
->where('bo.billet IN (:ids)') ->where('bo.billet IN (:ids)')
->andWhere('bb.isInvitation = false OR bb.isInvitation IS NULL') ->andWhere(self::DQL_BB_EXCLUDE_INVITATIONS)
->setParameter('ids', $billetIds) ->setParameter('ids', $billetIds)
->groupBy('bo.billet') ->groupBy('bo.billet')
->getQuery() ->getQuery()
@@ -484,7 +487,7 @@ class AccountController extends AbstractController
->leftJoin('o.items', 'i') ->leftJoin('o.items', 'i')
->where('o.event = :event') ->where('o.event = :event')
->andWhere('o.status = :status') ->andWhere('o.status = :status')
->andWhere('o.isInvitation = false OR o.isInvitation IS NULL') ->andWhere(self::DQL_EXCLUDE_INVITATIONS)
->setParameter('event', $event) ->setParameter('event', $event)
->setParameter('status', BilletBuyer::STATUS_PAID) ->setParameter('status', BilletBuyer::STATUS_PAID)
->getQuery() ->getQuery()
@@ -852,16 +855,11 @@ class AccountController extends AbstractController
$lastName = trim($request->request->getString('last_name')); $lastName = trim($request->request->getString('last_name'));
$email = trim($request->request->getString('email')); $email = trim($request->request->getString('email'));
$redirectResponse = $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'invitations']); $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']); $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; return $redirectResponse;
} }
@@ -912,7 +910,6 @@ class AccountController extends AbstractController
$billetOrderService->generateAndSendTickets($order); $billetOrderService->generateAndSendTickets($order);
$label = 'staff' === $accreditationType ? 'Staff' : 'Exposant';
$this->addFlash('success', 'Accreditation '.$label.' envoyee a '.$order->getEmail().'.'); $this->addFlash('success', 'Accreditation '.$label.' envoyee a '.$order->getEmail().'.');
return $redirectResponse; return $redirectResponse;
@@ -954,7 +951,7 @@ class AccountController extends AbstractController
$pdf = $billetOrderService->generatePdf($ticket); $pdf = $billetOrderService->generatePdf($ticket);
return new Response($pdf, 200, [ return new Response($pdf, 200, [
'Content-Type' => 'application/pdf', 'Content-Type' => self::CONTENT_TYPE_PDF,
'Content-Disposition' => 'inline; filename="'.$ticket->getReference().'.pdf"', 'Content-Disposition' => 'inline; filename="'.$ticket->getReference().'.pdf"',
]); ]);
} }
@@ -1010,16 +1007,8 @@ class AccountController extends AbstractController
$categoryIds = array_map('intval', $request->request->all('categories')); $categoryIds = array_map('intval', $request->request->all('categories'));
$billetIds = array_map('intval', $request->request->all('billets')); $billetIds = array_map('intval', $request->request->all('billets'));
$categories = []; $categories = $categoryIds ? $em->getRepository(Category::class)->findBy(['id' => $categoryIds, 'event' => $event]) : [];
if ($categoryIds) { $billets = $billetIds ? array_filter($em->getRepository(Billet::class)->findBy(['id' => $billetIds]), fn (Billet $b) => $b->getCategory()->getEvent()->getId() === $event->getId()) : [];
$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());
}
if (empty($categories) && empty($billets)) { if (empty($categories) && empty($billets)) {
$this->addFlash('error', 'Selectionnez au moins une categorie ou un billet.'); $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']); return $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'attestation']);
} }
$allBilletIds = []; [$billets, $allBilletIds] = $this->collectAttestationBillets($billets, $categories, $em);
foreach ($billets as $b) { [$billetLines, $totalSold] = $this->buildAttestationStats($billets, $allBilletIds, $em);
$allBilletIds[] = $b->getId(); $ticketDetails = $this->buildAttestationTicketDetails($allBilletIds, $em);
}
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;
$isSimple = 'simple' === $request->request->getString('mode', 'detail');
$generatedAt = new \DateTimeImmutable(); $generatedAt = new \DateTimeImmutable();
$selectedCategoryNames = array_map(fn ($c) => $c->getName(), $categories); $selectedCategoryNames = array_map(fn ($c) => $c->getName(), $categories);
@@ -1165,7 +1082,7 @@ class AccountController extends AbstractController
$dompdf->render(); $dompdf->render();
return new Response($dompdf->output(), 200, [ 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"', '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, [ 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"', 'Content-Disposition' => 'inline; filename="attestation_'.$payout->getStripePayoutId().'.pdf"',
]); ]);
} }
@@ -1525,6 +1442,103 @@ class AccountController extends AbstractController
return $order; return $order;
} }
/**
* @param list<Billet> $billets
* @param list<Category> $categories
*
* @return array{list<Billet>, list<int>}
*/
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<Billet> $billets
* @param list<int> $allBilletIds
*
* @return array{list<array<string, mixed>>, 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<int> $allBilletIds
*
* @return list<array<string, mixed>>
*/
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 private function requireEventOwnership(Event $event): User
{ {
/** @var User $user */ /** @var User $user */
@@ -1637,7 +1651,7 @@ class AccountController extends AbstractController
$filename = sprintf('recap_%04d_%02d.pdf', $year, $month); $filename = sprintf('recap_%04d_%02d.pdf', $year, $month);
return new Response($pdf, 200, [ return new Response($pdf, 200, [
'Content-Type' => 'application/pdf', 'Content-Type' => self::CONTENT_TYPE_PDF,
'Content-Disposition' => 'inline; filename="'.$filename.'"', 'Content-Disposition' => 'inline; filename="'.$filename.'"',
]); ]);
} }
@@ -1711,7 +1725,7 @@ class AccountController extends AbstractController
->from(BilletBuyer::class, 'o') ->from(BilletBuyer::class, 'o')
->join('o.event', 'e') ->join('o.event', 'e')
->where('e.account = :user') ->where('e.account = :user')
->andWhere('o.isInvitation = false OR o.isInvitation IS NULL') ->andWhere(self::DQL_EXCLUDE_INVITATIONS)
->setParameter('user', $user) ->setParameter('user', $user)
->getQuery() ->getQuery()
->getResult(); ->getResult();