<?php
namespace App\EventListener;
use App\Controller\AppController;
use App\Controller\VentourController;
use App\Controller\VentourVentourController;
use App\Entity\License;
use App\Exception\VentourApiControllerException;
use App\Helper\LicenseHelper;
use App\Helper\MuseumHelper;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use ReflectionClass;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Class VentourRequestChecker
* @package App\EventListener
*/
class VentourRequestChecker
{
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var LicenseHelper
*/
private $licenseHelper;
/**
* @var MuseumHelper
*/
private $museumHelper;
/**
* @var RouterInterface
*/
private $router;
/**
* @var TokenStorageInterface
*/
private $tokenStorage;
/**
* VentourRequestChecker constructor.
* @param LicenseHelper $licenseHelper
* @param MuseumHelper $museumHelper
* @param EntityManagerInterface $entityManager
* @param RouterInterface $router
* @param TokenStorageInterface $tokenStorage
* @param AuthorizationCheckerInterface $authorizationChecker
*/
public function __construct(
LicenseHelper $licenseHelper,
MuseumHelper $museumHelper,
EntityManagerInterface $entityManager,
RouterInterface $router,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $authorizationChecker
) {
$this->licenseHelper = $licenseHelper;
$this->entityManager = $entityManager;
$this->router = $router;
$this->museumHelper = $museumHelper;
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
}
/**
* @param ExceptionEvent $event
*/
public function onKernelException(ExceptionEvent $event)
{
$exception = $event->getThrowable();
if ($exception instanceof VentourApiControllerException) {
$errorCode = 400;
if ($exception->getCode() === VentourApiControllerException::MUSEUM_NOT_FOUND) {
$errorCode = 404;
}
$event->setResponse(new JsonResponse($exception->getErrorData(), $errorCode));
}
}
/**
* @param RequestEvent $event
* @throws \ReflectionException
* @throws Exception
*/
public function onKernelRequest(RequestEvent $event)
{
if ($event->isMasterRequest()) {
$license = $this->entityManager->getRepository(License::class)
->findByDomain($event->getRequest()->getHttpHost());
// Get controller class
/**
* @var string $controllerName
*/
$controllerName = explode('::', $event->getRequest()->attributes->get('_controller'))[0];
if (class_exists($controllerName)) {
// If a valid class (not the profiler, for example)
$controller = new ReflectionClass($controllerName);
// If a VentourController, validate data, else, redirect to the correct controller
if ($controller->isSubclassOf(new ReflectionClass(VentourController::class))) {
$this->checkLicense($event, $license, $controllerName, $controller);
$this->licenseHelper->init($license);
} elseif ($controllerName === AppController::class) {
if ($license->isVentourType()) {
$event->setResponse(new RedirectResponse($this->router->generate('select_museum')));
} elseif ($license->isAdminType()) {
$event->setResponse(new RedirectResponse($this->router->generate('home_admin')));
}
}
}
}
}
/**
* @param RequestEvent $event
* @param License $license
* @param string $controllerName
* @param ReflectionClass $controller
* @throws Exception
*/
private function checkLicense(
RequestEvent $event,
License $license,
string $controllerName,
ReflectionClass $controller
): void {
/**
* @var VentourController $controllerName
*/
if ($license->getType()->getType() !== $controllerName::getRequiredLicenseType()) {
$event->setResponse(new Response('', 404));
} elseif ($controller->isSubclassOf(new ReflectionClass(VentourVentourController::class))) {
if (!$license->getType()->isVentourType()) {
throw new Exception("'{$controllerName}' loaded in a '{$license->getType()}' license");
}
$this->checkMuseum($event);
}
}
/**
* @param RequestEvent $event
*/
private function checkMuseum(RequestEvent $event): void
{
if ($this->isUserLoggedIn()
&& $event->getRequest()->attributes->get('_route') !== 'select_museum'
&& $event->getRequest()->attributes->get('_route') !== 'selected_museum'
&& empty($this->museumHelper->getMuseum())) {
$url = $this->router->generate('select_museum', array(), RouterInterface::ABSOLUTE_URL);
$event->setResponse(new RedirectResponse($url));
}
}
/**
* @return bool
*/
private function isUserLoggedIn(): bool
{
return !empty($this->tokenStorage->getToken())
&& !empty($this->authorizationChecker->isGranted('ROLE_USER'));
}
}