<?php declare(strict_types=1);
namespace TRITUM\Noindex\Core;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Event\BeforeSendResponseEvent;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
class KernelResponseSubscriber implements EventSubscriberInterface
{
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var EntityRepositoryInterface
*/
private $seoUrlRepository;
public function __construct(SystemConfigService $systemConfigService, EntityRepositoryInterface $seoUrlRepository)
{
$this->systemConfigService = $systemConfigService;
$this->seoUrlRepository = $seoUrlRepository;
}
public static function getSubscribedEvents(): array
{
return [
BeforeSendResponseEvent::class => 'addNoindex',
];
}
public function addNoindex(BeforeSendResponseEvent $event): void
{
$requestUri = $event->getRequest()->getRequestUri();
if(!empty($requestUri)) {
$salesChannel = $event->getRequest()->attributes->get('sw-sales-channel-id');
$noIndexPages = explode("\n", $this->systemConfigService->get('TritumNoindex.config.pages', $salesChannel) ?? '');
$noIndexPagesWithSubpages = explode("\n", $this->systemConfigService->get('TritumNoindex.config.pagesSub', $salesChannel) ?? '');
if (!empty($noIndexPages) && !empty($noIndexPages[0])) {
foreach ($noIndexPages as $page) {
if (!empty($page)) {
$requestUri = $this->transformToSeoUrl($requestUri) ?? '';
$page = trim($page);
$page = $this->removeSlashesFromString($page);
if (preg_match("#\A/?$page/?\z#", $requestUri)) {
$response = $this->setNoindex($event->getResponse());
$event->setResponse($response);
}
}
}
}
if (!empty($noIndexPagesWithSubpages) && !empty($noIndexPagesWithSubpages[0])) {
foreach ($noIndexPagesWithSubpages as $pageWithSub) {
if (!empty($pageWithSub)) {
$requestUri = $this->transformToSeoUrl($requestUri);
$pageWithSub = trim($pageWithSub);
$pageWithSub = $this->addSlashesToString($pageWithSub);
if (preg_match("#\A$pageWithSub.*\z#", $requestUri)) {
$response = $this->setNoindex($event->getResponse());
$event->setResponse($response);
}
}
}
}
}
}
private function transformToSeoUrl($requestUri): string
{
if(preg_match( '#(.*)(\/\w+\/[0-9a-f]{32})$#', $requestUri, $matches)) {
$result = $this->seoUrlRepository->search(
(new Criteria())->addFilter(new EqualsFilter('pathInfo', $matches[2])), Context::createDefaultContext()
);
$resultCount = $result->count();
if ($resultCount === 1) {
$transformedURL = $result->getEntities()->first()->getSeoPathInfo();
} elseif ($resultCount === 0) {
return $requestUri;
}
$canonicalURL = $result->getEntities()->filterByProperty('isCanonical', true);
if ($canonicalURL->count() === 1) {
$transformedURL = $canonicalURL->first()->getSeoPathInfo();
}
if (empty($transformedURL)) $transformedURL = $result->getEntities()->last()->getSeoPathInfo();
if (substr($transformedURL, 0,1) !== '/') $transformedURL = '/' . $transformedURL;
return $matches[1] . $transformedURL;
} else {
return $requestUri;
}
}
private function setNoindex(Response $response): Response
{
$content = $response->getContent();
if (preg_match('#<meta\s+name="robots"\s+content="(.+)"\s*/>#', $content, $matches)) {
// noindex already set ?
if (strpos($matches[0], 'noindex') === false) {
if (strpos($matches[0], 'index') !== false) {
$replacement = str_replace('index', 'noindex', $matches[0]);
} else {
$replacement = '<meta name="robots" content="' . $matches[1] . ', noindex"/>';
}
$content = preg_replace('#<meta\s+name="robots"\s+content=".+"\s*/>#', $replacement, $content);
$response->setContent($content);
}
}
if ($response->headers->contains('x-robots-tag', 'noindex') === false) {
$response->headers->add(['x-robots-tag' => ['noindex']]);
}
return $response;
}
private function addSlashesToString($string): string
{
if (substr($string, 0,1) !== '/')
$string = '/' . $string;
if (substr($string, strlen($string) - 1, 1 ) !== '/')
$string .= '/';
return $string;
}
private function removeSlashesFromString($string): string
{
if (substr($string, 0,1) === '/')
$string = rtrim($string, '/');
if (substr($string, strlen($string) - 1, 1 ) !== '/')
$string = ltrim($string, '/');
return $string;
}
}