<?php
namespace App\Controller;
use App\Entity\Page;
use App\Entity\Path;
use App\Entity\Tag;
use App\Repository\PageRepository;
use App\Repository\PathRepository;
use App\Repository\TagRepository;
use App\Service\CacheService;
use App\Service\PageService;
use App\Service\SiteMapService;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Cache\InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
#[Route('/')]
class FrontController extends AbstractController
{
/**
* FrontController constructor.
*/
public function __construct(
protected CacheService $cacheService,
protected PageService $pageService,
protected SiteMapService $siteMapService,
protected ManagerRegistry $registry,
private readonly CsrfTokenManagerInterface $csrfTokenManager)
{
}
#[Route('/debug/{slug}', name: 'front_index_debug')]
public function debug(Request $request): Response
{
// replace this example code with whatever you need
return $this->render('front/layout/debug/'.$request->get('slug').'.html.twig');
}
/**
* @throws \Exception
*/
#[Route('sitemap.xml', name: 'front_siteMap_index')]
public function siteMapMain(Request $request): Response
{
/** @var PageRepository $pageRepository */
$pageRepository = $this->registry->getRepository(Page::class);
$xml = $this->siteMapService->getTree($pageRepository, $request->getSchemeAndHttpHost());
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
return $response;
}
/**
* @throws NonUniqueResultException
* @throws \Exception
*/
#[Route('sitemap-{type}.xml', name: 'front_siteMap_type', requirements: ['type' => ".+[^\/]"])]
public function siteMapType(Request $request, string $type): Response
{
/** @var PageRepository $pageRepository */
$pageRepository = $this->registry->getRepository(Page::class);
if (!$pageRepository->findType($type) && 'main' !== $type) {
throw $this->createNotFoundException('Page not found');
}
$xml = $this->siteMapService->getTypeTree($pageRepository, $request->getSchemeAndHttpHost(), $type);
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
return $response;
}
#[Route('/amp', name: 'front_root_amp')]
public function rootAmp(Request $request): Response
{
return $this->forward('App\\Controller\\FrontController::index', [
'request' => $request,
'path' => '',
]);
}
#[Route('/{path}/amp', name: 'front_index_amp', requirements: ['path' => ".+[^\/]"])]
public function indexAmp(Request $request, string $path = ''): Response
{
return $this->forward('App\\Controller\\FrontController::index', [
'request' => $request,
'path' => $path,
'amp' => true,
]);
}
/**
* @throws NonUniqueResultException
* @throws InvalidArgumentException
*/
#[Route('/{path}/page/{pagination}', name: 'front_index_paginated', requirements: ['path' => ".+[^\/]"])]
public function indexPaginated(Request $request, string $path = '', int $pagination = 1, bool $amp = false): RedirectResponse|Response
{
return $this->handleRequest($request, $path, $amp, $pagination);
}
/**
* @throws NonUniqueResultException
* @throws InvalidArgumentException
*/
#[Route('/{path}', name: 'front_index', requirements: ['type' => ".+[^\/]", 'path' => '^((?!logout).)*$'])]
public function index(Request $request, string $path = '', bool $amp = false): RedirectResponse|Response
{
return $this->handleRequest($request, $path, $amp);
}
/**
* @throws NonUniqueResultException
* @throws InvalidArgumentException
*/
private function handleRequest(Request $request, string $path = '', bool $amp = false, int $pagination = 1): RedirectResponse|Response
{
/** @var PathRepository $pathRepository */
$pathRepository = $this->registry->getRepository(Path::class);
/** @var PageRepository $pageRepository */
$pageRepository = $this->registry->getRepository(Page::class);
/** @var TagRepository $tagRepository */
$tagRepository = $this->registry->getRepository(Tag::class);
$path = $pathRepository->findOneSingleByPath($path, $request->getLocale());
if (!$path) {
throw $this->createNotFoundException('Page not found');
}
if (Path::TYPE_REDIRECT == $path->getType()) {
/** @var Page $page */
$page = $path->getPage();
if (null == $page || null == $page->getCurrentPath()) {
throw $this->createNotFoundException('Page not found');
}
return new RedirectResponse($this->pageService->getFrontUrl($page));
}
/** @var Page $page */
$page = $path->getPage();
$preview = $request->query->get('preview');
if ($preview) {
if (!$this->isGranted('preview', $page)) {
throw $this->createNotFoundException('Page not found');
}
$user = $this->getUser();
$cacheKey = $this->cacheService->getPreviewCacheKey($user->getId(), $page->getId(), $page->getType());
$data = $this->cacheService->getAdapter()->getItem($cacheKey);
if ($data->isHit()) {
$page->import($data->get());
}
} else {
if (!$this->isGranted('see-front', $page)) {
throw $this->createNotFoundException('Page not found');
}
}
$page = $this->pageService->resolveData($page, $pageRepository, $tagRepository);
$params = [
'page' => $page,
];
$params['pagination'] = $pagination;
if ($page instanceof Page) {
$params = $this->generateContentForSEO($request, $page, $pageRepository, $params);
}
return $this->render('front/layout/'.(($amp) ? 'amp/' : '').$page->getType().'.html.twig', $params);
}
/**
* @throws \Exception
*/
public function pages(Request $request, string $type, int $offset = 0, int $limit = 10): Response
{
$locale = $request->getLocale();
/** @var PageRepository $pageRepository */
$pageRepository = $this->registry->getRepository(Page::class);
$filters = [
'locale' => [$locale],
'status' => ['published'],
'visibility' => 'public',
'expiration' => ['active'],
];
$orderBy = ['created' => 'DESC'];
$items = $pageRepository->paginate($type, $filters, $orderBy, $limit, $offset * $limit);
return $this->render('front/section/'.$type.'.html.twig', [
'items' => $items,
'currentPage' => $offset,
]);
}
public function generateContentForSEO(Request $request, Page $page, PageRepository $pageRepository, array $params): array
{
switch ($page->getType()) {
case 'publications-list':
$offset = $request->query->get('page');
if ($offset === null) {
$offset = 1;
}
$types = [
"barometer-activity",
"activity-report",
"study",
"thematic-brochure",
"practical-guide",
"btob-news"
];
$publications = $pageRepository->paginateListPages($types, (int)$offset, 12);
$totalPublications = $pageRepository->countPages($types);
$params['publications'] = $publications;
$params['pagination'] = [
'offset' => $offset,
'totalPages' => ceil($totalPublications[0][1] / 12)
];
break;
case 'news-list':
$offset = $request->query->get('page');
if ($offset === null) {
$offset = 1;
}
$types = [
"agenda",
"event",
"article"
];
$publications = $pageRepository->paginateListPages($types, (int)$offset, 12);
$totalPublications = $pageRepository->countPages($types);
$params['publications'] = $publications;
$params['pagination'] = [
'offset' => $offset,
'totalPages' => ceil($totalPublications[0][1] / 12)
];
break;
}
return $params;
}
public function generateCSRF(string $key, ?string $fieldName): Response
{
$token = $this->csrfTokenManager->getToken($key)->getValue();
$response = $this->render('front/partials/csrf-token.html.twig', [
'token' => $token,
'name' => $fieldName
]);
$response->setPublic();
$response->setCache([
'no_cache' => true,
'max_age' => 0,
'must_revalidate' => true,
'no_store' => true
]);
return $response;
}
}