<?php
namespace Lnb\Shopware6\LnbRedirect\Subscriber;
use Doctrine\DBAL\Connection;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class KernelRequestSubscriber implements EventSubscriberInterface
{
private Connection $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 35] // before RouterListener and after StorefrontSubscriber because we need the session
];
}
public function onKernelRequest(RequestEvent $event): void
{
try {
if (!$event->getRequest()->getSession() instanceof SessionInterface) {
return;
}
} catch (SessionNotFoundException $e) { //important to catch this
return;
}
$pathInfo = $event->getRequest()->attributes->get('sw-original-request-uri');
if (!$pathInfo) {
return;
}
$pathInfo = substr($pathInfo, 1);
$salesChannelId = $event->getRequest()->getSession()->get('sw-sales-channel-id');
if (!$salesChannelId) {
return;
}
if ($this->hasTrailingSlash($pathInfo) || !$this->isSeoUrl($pathInfo, $salesChannelId)) {
return;
}
$event->stopPropagation(); //important to stop propagation
$response = new RedirectResponse($event->getRequest()->getSchemeAndHttpHost() . '/' . $pathInfo . '/', 301); //redirect to absolute url
$response->send();
}
private function hasTrailingSlash(string $pathInfo): bool
{
return str_ends_with($pathInfo, '/');
}
private function isSeoUrl(string $pathInfo, string $salesChannelId): bool
{
$query = "SELECT count(id) as count
FROM `seo_url`
WHERE `seo_path_info` = :seo_path_info AND `sales_channel_id` = UNHEX(:sales_channel_id) AND `is_canonical` = '1'";
try {
$result = $this->connection
->prepare($query)
->executeQuery(['sales_channel_id' => $salesChannelId, 'seo_path_info' => $pathInfo . '/']);
return $result->fetchOne() > 0;
} catch (\Exception $e) {
return false;
}
}
}