Optimize N+1 queries: batch billets, soldCounts, paid orders with items
- AccountController: single query for all billets by categories, single GROUP BY query for sold counts, eager-load items on paid orders - HomeController: single query for all buyable billets of active categories Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
- [x] Rate limiting sur les routes sensibles (login 5/15min, commande 10/5min, invitation 5/15min, contact 3/10min)
|
||||
- [x] CSRF token sur tous les formulaires POST (auto-inject + auto-verify)
|
||||
- [x] Cache Meilisearch : invalider quand un événement est modifié (déjà fait via EventIndexService::indexEvent)
|
||||
- [ ] Optimiser les requêtes N+1 (stats tab, billets par catégorie)
|
||||
- [x] Optimiser les requêtes N+1 (stats tab, billets par catégorie)
|
||||
|
||||
### Tests
|
||||
- [ ] Atteindre 90%+ de couverture PHP
|
||||
|
||||
@@ -374,13 +374,29 @@ class AccountController extends AbstractController
|
||||
['position' => 'ASC'],
|
||||
);
|
||||
|
||||
$allBillets = $em->getRepository(Billet::class)->findBy(['category' => $categories], ['position' => 'ASC']);
|
||||
|
||||
$billets = [];
|
||||
$billetIds = [];
|
||||
foreach ($allBillets as $billet) {
|
||||
$catId = $billet->getCategory()->getId();
|
||||
$billets[$catId][] = $billet;
|
||||
$billetIds[] = $billet->getId();
|
||||
}
|
||||
|
||||
$soldCounts = [];
|
||||
foreach ($categories as $category) {
|
||||
$categoryBillets = $em->getRepository(Billet::class)->findBy(['category' => $category], ['position' => 'ASC']);
|
||||
$billets[$category->getId()] = $categoryBillets;
|
||||
foreach ($categoryBillets as $billet) {
|
||||
$soldCounts[$billet->getId()] = $em->getRepository(BilletOrder::class)->count(['billet' => $billet]);
|
||||
if ($billetIds) {
|
||||
$rows = $em->createQueryBuilder()
|
||||
->select('IDENTITY(bo.billet) AS billetId, COUNT(bo.id) AS cnt')
|
||||
->from(BilletOrder::class, 'bo')
|
||||
->where('bo.billet IN (:ids)')
|
||||
->setParameter('ids', $billetIds)
|
||||
->groupBy('bo.billet')
|
||||
->getQuery()
|
||||
->getArrayResult();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$soldCounts[$row['billetId']] = (int) $row['cnt'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +406,16 @@ class AccountController extends AbstractController
|
||||
: $em->getRepository(BilletBuyer::class)->findBy(['event' => $event], ['createdAt' => 'DESC']);
|
||||
$eventOrders = $paginator->paginate($ordersQuery, $request->query->getInt('page', 1), 20);
|
||||
|
||||
$paidEventOrders = $em->getRepository(BilletBuyer::class)->findBy(['event' => $event, 'status' => BilletBuyer::STATUS_PAID]);
|
||||
$paidEventOrders = $em->createQueryBuilder()
|
||||
->select('o', 'i')
|
||||
->from(BilletBuyer::class, 'o')
|
||||
->leftJoin('o.items', 'i')
|
||||
->where('o.event = :event')
|
||||
->andWhere('o.status = :status')
|
||||
->setParameter('event', $event)
|
||||
->setParameter('status', BilletBuyer::STATUS_PAID)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
$eventStats = $this->computeEventStats($paidEventOrders);
|
||||
|
||||
return $this->render('account/edit_event.html.twig', [
|
||||
|
||||
@@ -147,16 +147,15 @@ class HomeController extends AbstractController
|
||||
['position' => 'ASC'],
|
||||
);
|
||||
|
||||
$activeCategories = array_filter($categories, fn (Category $c) => $c->isActive());
|
||||
$allBillets = $activeCategories ? $em->getRepository(Billet::class)->findBy(
|
||||
['category' => $activeCategories, 'notBuyable' => false],
|
||||
['position' => 'ASC'],
|
||||
) : [];
|
||||
|
||||
$billets = [];
|
||||
foreach ($categories as $category) {
|
||||
if (!$category->isActive()) {
|
||||
continue;
|
||||
}
|
||||
$categoryBillets = $em->getRepository(Billet::class)->findBy(
|
||||
['category' => $category],
|
||||
['position' => 'ASC'],
|
||||
);
|
||||
$billets[$category->getId()] = array_filter($categoryBillets, fn (Billet $b) => !$b->isNotBuyable());
|
||||
foreach ($allBillets as $billet) {
|
||||
$billets[$billet->getCategory()->getId()][] = $billet;
|
||||
}
|
||||
|
||||
return $this->render('home/event_detail.html.twig', [
|
||||
|
||||
Reference in New Issue
Block a user