src/Controller/Frontend/RankingController.php line 49

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Frontend;
  3. use App\Controller\Shared\Ranking\CalculateRankingCached;
  4. use App\Entity\Backend\Club;
  5. use App\Entity\Gestion\Ranking;
  6. use App\Web\Ranking\Application\Service\RankingPdfGenerationPublisher;
  7. use App\Web\Ranking\Domain\RankingPdfGenerator;
  8. use App\Web\Ranking\Domain\RankingPdfStorage;
  9. use Doctrine\ORM\EntityManagerInterface;
  10. use Psr\Log\LoggerInterface;
  11. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  12. use Symfony\Component\HttpFoundation\RedirectResponse;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  15. use Symfony\Component\Routing\Annotation\Route;
  16. use Symfony\Component\String\Slugger\AsciiSlugger;
  17. class RankingController extends AbstractController {
  18. public function __construct(private readonly EntityManagerInterface $em)
  19. {
  20. }
  21. /**
  22. * F-122 Visualización del ranking
  23. *
  24. * @Route("/ranking/{id}", name="ranking", options={"expose"=true})
  25. */
  26. public function ranking($id, CalculateRankingCached $calculateRankingCached): RedirectResponse|Response
  27. {
  28. $id = intval($id);
  29. $ranking = $this->em->getRepository(Ranking::class)->find($id);
  30. if (!$ranking) {
  31. $this->addFlash(
  32. 'error', "El ranking seleccionado no existe");
  33. return $this->redirect($this->generateUrl('portada'));
  34. }
  35. $params = $calculateRankingCached->__invoke($id, false, $ranking);
  36. return $this->render("frontend/Ranking/ranking.html.twig", $params);
  37. }
  38. /**
  39. * @Route("/ranking/{id}/pdf/{filename}", name="ranking_pdf", requirements={"id": "\d+", "filename": ".+\.pdf"}, defaults={"filename"=null})
  40. */
  41. public function rankingPdf(
  42. $id,
  43. ?string $filename,
  44. RankingPdfGenerator $rankingPdfGenerator,
  45. RankingPdfStorage $rankingPdfStorage,
  46. RankingPdfGenerationPublisher $rankingPdfGenerationPublisher,
  47. LoggerInterface $logger,
  48. ): RedirectResponse|Response {
  49. $id = intval($id);
  50. $ranking = $this->em->getRepository(Ranking::class)->find($id);
  51. if (!$ranking) {
  52. $this->addFlash('error', "El ranking seleccionado no existe");
  53. return $this->redirect($this->generateUrl('portada'));
  54. }
  55. if (!$ranking->getActivo() && !$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_FEDE') && !$this->isGranted('ROLE_CLUB')) {
  56. throw $this->createAccessDeniedException();
  57. }
  58. $pdfFilename = $this->pdfFilename($ranking);
  59. if ($filename !== $pdfFilename) {
  60. return $this->redirectToRoute('ranking_pdf', [
  61. 'id' => $ranking->getId(),
  62. 'filename' => $pdfFilename,
  63. ]);
  64. }
  65. try {
  66. $downloadUrl = $rankingPdfStorage->temporaryDownloadUrl(
  67. (int) $ranking->getId(),
  68. $ranking->getPdfRevision(),
  69. $pdfFilename
  70. );
  71. if (null !== $downloadUrl) {
  72. $response = new RedirectResponse($downloadUrl);
  73. $response->headers->set('X-Robots-Tag', 'noindex');
  74. return $response;
  75. }
  76. } catch (\Throwable $exception) {
  77. // S3 is only a cache. Its failure must never prevent the current
  78. // synchronous PDF generation from serving the user.
  79. $logger->warning('Ranking PDF storage is unavailable; using synchronous generation.', [
  80. 'ranking_id' => $ranking->getId(),
  81. 'revision' => $ranking->getPdfRevision(),
  82. 'exception' => $exception,
  83. ]);
  84. }
  85. $rankingPdfGenerationPublisher->publish((int) $ranking->getId(), $ranking->getPdfRevision());
  86. $pdf = $rankingPdfGenerator->generate($ranking);
  87. $response = new Response($pdf);
  88. $response->headers->set('Content-Type', 'application/pdf');
  89. $response->headers->set(
  90. 'Content-Disposition',
  91. $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_INLINE, $pdfFilename)
  92. );
  93. $response->headers->set('X-Robots-Tag', 'noindex');
  94. return $response;
  95. }
  96. private function pdfFilename(Ranking $ranking): string
  97. {
  98. $filename = (new AsciiSlugger())
  99. ->slug((string) $ranking->getNombre(), '-')
  100. ->lower()
  101. ->toString();
  102. if ($filename === '') {
  103. $filename = 'ranking-' . $ranking->getId();
  104. }
  105. return $filename . '.pdf';
  106. }
  107. /**
  108. * F-123 Visualización de los rankings de un club
  109. *
  110. * @Route("/rankings-club/{id}", name="rankings_club")
  111. */
  112. public function rankingsClub($id): RedirectResponse|Response
  113. {
  114. $club = $this->em->getRepository(Club::class)->find($id);
  115. if (!$club) {
  116. $this->addFlash('error', "No encontramos el Club que nos ha solicitado");
  117. return $this->redirect($this->generateUrl('provincias'));
  118. }
  119. $isFederation = $club->isFederationClub();
  120. $clientId = $isFederation ? $club->getCliente()->getId() : null;
  121. $rankings = $this->em->getRepository(Ranking::class)->obtainRankingsByClubOrClient($club->getId(), $clientId, $isFederation, false);
  122. return $this->render("frontend/Ranking/rankingsClub.html.twig", [
  123. "rankings" => $rankings,
  124. "club" => $club
  125. ]);
  126. }
  127. }