src/Controller/SearchController.php line 22

Open in your IDE?
  1. <?php
  2. // src/Controller/SearchController.php
  3. namespace App\Controller;
  4. use App\Entity\Acte;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\JsonResponse;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpFoundation\Response;
  10. use Symfony\Component\Routing\Annotation\Route;
  11. class SearchController extends AbstractController
  12. {
  13. public function __construct(private EntityManagerInterface $em) {}
  14. // ──────────────────────────────────────────────────────────────────────────
  15. // Route principale SSR
  16. // ──────────────────────────────────────────────────────────────────────────
  17. #[Route('/search', name: 'app_search', methods: ['GET'])]
  18. public function index(Request $request): Response
  19. {
  20. $params = $this->extractParams($request);
  21. $isPremium = $this->getUser()?->hasPremiumAccess() ?? false;
  22. $results = [];
  23. $total = 0;
  24. $totalPages = 0;
  25. if ($params['q'] !== '' || $this->hasActiveFilter($params)) {
  26. [$results, $total] = $this->runSearch($params, $isPremium);
  27. $totalPages = (int) ceil($total / 15);
  28. }
  29. return $this->render('search/index.html.twig', [
  30. 'query' => $params['q'],
  31. 'results' => $results,
  32. 'filters' => $params,
  33. 'typeFilter' => $params['type'],
  34. 'currentPage' => $params['page'],
  35. 'totalPages' => $totalPages,
  36. 'isPremium' => $isPremium,
  37. ]);
  38. }
  39. // ──────────────────────────────────────────────────────────────────────────
  40. // Route AJAX — JSON (live search + autocomplete)
  41. // ──────────────────────────────────────────────────────────────────────────
  42. #[Route('/munganyo/api', name: 'app_search_ajax', methods: ['GET'])]
  43. public function ajax(Request $request): JsonResponse
  44. {
  45. if (!$request->isXmlHttpRequest() && !$request->query->getBoolean('autocomplete')) {
  46. return $this->json(['error' => 'Requête non autorisée'], 403);
  47. }
  48. $params = $this->extractParams($request);
  49. $isPremium = $this->getUser()?->hasPremiumAccess() ?? false;
  50. // ── Mode autocomplete ─────────────────────────────────────────────────
  51. if ($request->query->getBoolean('autocomplete')) {
  52. $limit = min((int) $request->query->get('limit', 6), 10);
  53. return $this->json(['suggestions' => $this->runAutocomplete($params['q'], $limit)]);
  54. }
  55. // ── Recherche complète ────────────────────────────────────────────────
  56. $perPage = 15;
  57. [$actes, $total] = $this->runSearch($params, $isPremium, $perPage);
  58. return $this->json([
  59. 'results' => array_map(fn($a) => $this->serializeActe($a, $isPremium), $actes),
  60. 'total' => $total,
  61. 'currentPage' => $params['page'],
  62. 'totalPages' => (int) ceil($total / $perPage),
  63. 'isPremium' => $isPremium,
  64. ]);
  65. }
  66. // ──────────────────────────────────────────────────────────────────────────
  67. // Logique de recherche — QueryBuilder inline (pas de repository)
  68. // ──────────────────────────────────────────────────────────────────────────
  69. private function runSearch(array $params, bool $isPremium, int $perPage = 15): array
  70. {
  71. // TODO: décommenter quand les entités seront créées
  72. return [[], 0];
  73. }
  74. // ──────────────────────────────────────────────────────────────────────────
  75. // Autocomplete inline
  76. // ──────────────────────────────────────────────────────────────────────────
  77. private function runAutocomplete(string $query, int $limit): array
  78. {
  79. return [];
  80. }
  81. // ──────────────────────────────────────────────────────────────────────────
  82. // Sérialisation — OCR et pertinence réservés au Premium (CDC)
  83. // ──────────────────────────────────────────────────────────────────────────
  84. private function serializeActe(object $acte, bool $isPremium): array
  85. {
  86. $data = [
  87. 'id' => $acte->getId(),
  88. 'titre' => $acte->getTitre(),
  89. 'numero' => $acte->getNumeroActe(),
  90. 'type' => $acte->getTypeActe()?->getCode(),
  91. 'typeLabel' => $acte->getTypeActe()?->getLabel(),
  92. 'datePublication' => $acte->getDatePublication()?->format('Y-m-d'),
  93. 'institution' => $acte->getInstitutionEmettrice()?->getNom(),
  94. 'territoire' => $acte->getTerritoireApplicable()?->getNom(),
  95. 'statutJuridique' => $acte->getStatutJuridique()?->getCode(),
  96. 'resume' => $acte->getResume(),
  97. 'pdf_url' => $acte->getPdfUrl(),
  98. ];
  99. if ($isPremium) {
  100. $data['extrait'] = $acte->getExtraitPertinent();
  101. $data['relevance'] = $acte->getRelevanceScore();
  102. }
  103. return $data;
  104. }
  105. // ──────────────────────────────────────────────────────────────────────────
  106. // Helpers privés
  107. // ──────────────────────────────────────────────────────────────────────────
  108. private function extractParams(Request $r): array
  109. {
  110. return [
  111. 'q' => trim($r->query->get('q', '')),
  112. 'institution' => $r->query->get('institution', ''),
  113. 'period' => $r->query->get('period', ''),
  114. 'date_debut' => $r->query->get('date_debut', ''),
  115. 'date_fin' => $r->query->get('date_fin', ''),
  116. 'type' => $r->query->get('type', ''),
  117. 'statut' => $r->query->get('statut', ''),
  118. 'territoire' => $r->query->get('territoire', ''),
  119. 'sort' => $r->query->get('sort', 'date_desc'),
  120. 'page' => max(1, (int) $r->query->get('page', 1)),
  121. ];
  122. }
  123. private function hasActiveFilter(array $params): bool
  124. {
  125. foreach (['institution', 'type', 'statut', 'territoire', 'period'] as $key) {
  126. if ($params[$key] !== '') return true;
  127. }
  128. return false;
  129. }
  130. }