<?php declare(strict_types=1);
namespace Acris\SeoRedirect\Subscriber;
use Acris\SeoRedirect\Components\RedirectService;
use Acris\SeoRedirect\Storefront\Framework\Routing\RequestTransformer;
use Shopware\Core\Framework\Routing\RequestTransformerInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Framework\Routing\Exception\SalesChannelMappingException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class PageNotFoundExceptionSubscriber implements EventSubscriberInterface
{
private RedirectService $redirectService;
private SystemConfigService $configService;
private RequestTransformerInterface $storefrontRequestTransformer;
public function __construct(RedirectService $redirectService, SystemConfigService $configService, RequestTransformerInterface $storefrontRequestTransformer)
{
$this->redirectService = $redirectService;
$this->configService = $configService;
$this->storefrontRequestTransformer = $storefrontRequestTransformer;
}
// -59, so that it is before RouterListener and in between to allow other possible listeners.
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => [
['onKernelException', -59],
],
];
}
public function onKernelException(ExceptionEvent $event)
{
$redirectConfig = $this->configService->get('AcrisSeoRedirectCS.config.redirectCheckPlace');
if ($redirectConfig == 'notFoundPage' && $this->isNotFoundPage($event->getThrowable())) {
$request = $this->getTransformedRequest($event->getRequest());
$orgRequest = Request::createFromGlobals();
if ($this->redirectService->checkRedirect($request, $orgRequest)) {
$event->setResponse(new RedirectResponse($request->attributes->get(RequestTransformer::REQUEST_ATTRIBUTE_SEO_REDIRECT_URL), $request->attributes->get(RequestTransformer::REQUEST_ATTRIBUTE_SEO_REDIRECT_CODE)));
}
}
}
private function isNotFoundPage(\Throwable $exception): bool
{
return !empty($exception) && method_exists($exception, 'getStatusCode') && !empty($exception->getStatusCode()) && $exception->getStatusCode() === Response::HTTP_NOT_FOUND;
}
private function getTransformedRequest(Request $orgRequest): Request
{
try {
$request = $this->storefrontRequestTransformer->transform($orgRequest);
} catch (SalesChannelMappingException $salesChannelMappingException) {
$isRedirected = $this->redirectService->checkRedirect($orgRequest, $orgRequest);
if($isRedirected === true) {
return $orgRequest;
}
// if not redirect, throw sales channel not found exception again
throw $salesChannelMappingException;
}
return $request;
}
}