<?php
namespace App\Controller\Frontend;
use App\Controller\Shared\Ranking\CalculateRankingCached;
use App\Entity\Backend\Club;
use App\Entity\Gestion\Ranking;
use App\Web\Ranking\Application\Service\RankingPdfGenerationPublisher;
use App\Web\Ranking\Domain\RankingPdfGenerator;
use App\Web\Ranking\Domain\RankingPdfStorage;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\String\Slugger\AsciiSlugger;
class RankingController extends AbstractController {
public function __construct(private readonly EntityManagerInterface $em)
{
}
/**
* F-122 Visualización del ranking
*
* @Route("/ranking/{id}", name="ranking", options={"expose"=true})
*/
public function ranking($id, CalculateRankingCached $calculateRankingCached): RedirectResponse|Response
{
$id = intval($id);
$ranking = $this->em->getRepository(Ranking::class)->find($id);
if (!$ranking) {
$this->addFlash(
'error', "El ranking seleccionado no existe");
return $this->redirect($this->generateUrl('portada'));
}
$params = $calculateRankingCached->__invoke($id, false, $ranking);
return $this->render("frontend/Ranking/ranking.html.twig", $params);
}
/**
* @Route("/ranking/{id}/pdf/{filename}", name="ranking_pdf", requirements={"id": "\d+", "filename": ".+\.pdf"}, defaults={"filename"=null})
*/
public function rankingPdf(
$id,
?string $filename,
RankingPdfGenerator $rankingPdfGenerator,
RankingPdfStorage $rankingPdfStorage,
RankingPdfGenerationPublisher $rankingPdfGenerationPublisher,
LoggerInterface $logger,
): RedirectResponse|Response {
$id = intval($id);
$ranking = $this->em->getRepository(Ranking::class)->find($id);
if (!$ranking) {
$this->addFlash('error', "El ranking seleccionado no existe");
return $this->redirect($this->generateUrl('portada'));
}
if (!$ranking->getActivo() && !$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_FEDE') && !$this->isGranted('ROLE_CLUB')) {
throw $this->createAccessDeniedException();
}
$pdfFilename = $this->pdfFilename($ranking);
if ($filename !== $pdfFilename) {
return $this->redirectToRoute('ranking_pdf', [
'id' => $ranking->getId(),
'filename' => $pdfFilename,
]);
}
try {
$downloadUrl = $rankingPdfStorage->temporaryDownloadUrl(
(int) $ranking->getId(),
$ranking->getPdfRevision(),
$pdfFilename
);
if (null !== $downloadUrl) {
$response = new RedirectResponse($downloadUrl);
$response->headers->set('X-Robots-Tag', 'noindex');
return $response;
}
} catch (\Throwable $exception) {
// S3 is only a cache. Its failure must never prevent the current
// synchronous PDF generation from serving the user.
$logger->warning('Ranking PDF storage is unavailable; using synchronous generation.', [
'ranking_id' => $ranking->getId(),
'revision' => $ranking->getPdfRevision(),
'exception' => $exception,
]);
}
$rankingPdfGenerationPublisher->publish((int) $ranking->getId(), $ranking->getPdfRevision());
$pdf = $rankingPdfGenerator->generate($ranking);
$response = new Response($pdf);
$response->headers->set('Content-Type', 'application/pdf');
$response->headers->set(
'Content-Disposition',
$response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_INLINE, $pdfFilename)
);
$response->headers->set('X-Robots-Tag', 'noindex');
return $response;
}
private function pdfFilename(Ranking $ranking): string
{
$filename = (new AsciiSlugger())
->slug((string) $ranking->getNombre(), '-')
->lower()
->toString();
if ($filename === '') {
$filename = 'ranking-' . $ranking->getId();
}
return $filename . '.pdf';
}
/**
* F-123 Visualización de los rankings de un club
*
* @Route("/rankings-club/{id}", name="rankings_club")
*/
public function rankingsClub($id): RedirectResponse|Response
{
$club = $this->em->getRepository(Club::class)->find($id);
if (!$club) {
$this->addFlash('error', "No encontramos el Club que nos ha solicitado");
return $this->redirect($this->generateUrl('provincias'));
}
$isFederation = $club->isFederationClub();
$clientId = $isFederation ? $club->getCliente()->getId() : null;
$rankings = $this->em->getRepository(Ranking::class)->obtainRankingsByClubOrClient($club->getId(), $clientId, $isFederation, false);
return $this->render("frontend/Ranking/rankingsClub.html.twig", [
"rankings" => $rankings,
"club" => $club
]);
}
}