<?php declare(strict_types=1);
namespace MageWorx\SeoCrosslinks\Subscriber;
use MageWorx\SeoCrosslinks\Core\Content\Crosslink\Service\SalesChannelContextProvider;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Storefront\Page\LandingPage\LandingPage;
use Shopware\Storefront\Page\LandingPage\LandingPageLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use MageWorx\SeoCrosslinks\Core\Content\Crosslink\Service\CrosslinkReplacer;
class LandingPageSubscriber implements EventSubscriberInterface
{
protected RequestStack $requestStack;
protected SystemConfigService $systemConfig;
protected EntityRepositoryInterface $crosslinkRepository;
protected CrosslinkReplacer $replacer;
private SalesChannelContextProvider $salesChannelContextProvider;
public function __construct(
EntityRepositoryInterface $crosslinkRepository,
SystemConfigService $systemConfigService,
RequestStack $requestStack,
CrosslinkReplacer $replacer,
SalesChannelContextProvider $salesChannelContextProvider
) {
$this->crosslinkRepository = $crosslinkRepository;
$this->requestStack = $requestStack;
$this->systemConfig = $systemConfigService;
$this->replacer = $replacer;
$this->salesChannelContextProvider = $salesChannelContextProvider;
}
public static function getSubscribedEvents(): array
{
return [
LandingPageLoadedEvent::class => 'onLandingPagesLoaded'
];
}
public function onLandingPagesLoaded($event)
{
if (!$this->isAllow()) {
return;
}
$maxReplaceCount = $this->systemConfig->getInt('MageWorxSeoCrosslinks.config.pageMaxReplacementCount');
if ($maxReplaceCount === 0) {
return;
}
$landingPageId = $this->requestStack->getMainRequest()->attributes->get('landingPageId');
/** @var LandingPage $page */
$page = $event->getPage();
if ($page) {
$cmsPage = $page->getCmsPage();
if ($cmsPage) {
$pairs = $this->composePairs($cmsPage);
if ($pairs) {
$content = $this->compactParts($pairs);
$modContent = $this->getModifiedContent(
$content,
$landingPageId,
$event->getContext(),
$maxReplaceCount
);
if ($modContent) {
$pairs = $this->extractParts($modContent, $pairs);
$this->applyPairs($cmsPage, $pairs);
}
}
}
}
}
protected function composePairs($cmsPage): array
{
$pairs = [];
if ($cmsPage->getSections()) {
foreach ($cmsPage->getSections()->getElements() as $cmsSectionEntity) {
if ($cmsSectionEntity->getBlocks()) {
/** @var CmsBlockEntity $cmsBlock */
foreach ($cmsSectionEntity->getBlocks()->getElements() as $cmsBlock) {
if ($cmsBlock->getSlots()) {
foreach ($cmsBlock->getSlots() as $slotId => $slot) {
if ($slot->getData() && $slot->getData()->getContent()) {
$pairs[$slotId] = $slot->getData()->getContent();
}
}
}
}
}
}
}
return $pairs;
}
protected function applyPairs(CmsPageEntity $cmsPage, array $pairs): void
{
if ($cmsPage->getSections()) {
foreach ($cmsPage->getSections()->getElements() as $cmsSectionEntity) {
if ($cmsSectionEntity->getBlocks()) {
/** @var CmsBlockEntity $cmsBlock */
foreach ($cmsSectionEntity->getBlocks()->getElements() as $cmsBlock) {
if ($cmsBlock->getSlots()) {
foreach ($cmsBlock->getSlots() as $slotId => $slot) {
if (!array_key_exists($slotId, $pairs)) {
continue;
}
$slot->getData()->setContent($pairs[$slotId]);
}
}
}
}
}
}
}
/**
* @param array $pairs
* @return string
*/
protected function compactParts(array $pairs): string
{
$result = '';
$firstFlag = true;
foreach ($pairs as $id => $content) {
if (!$firstFlag) {
$result .= $id;
}
$result .= $content;
$firstFlag = false;
}
return $result;
}
protected function extractParts(string $content, array $pairs): array
{
$regexp = "/" . implode('|', array_keys($pairs)) . "/";
$parts = preg_split($regexp, $content);
return array_combine(array_keys($pairs), $parts);
}
protected function isAllow(): bool
{
if ($this->systemConfig->getBool('MageWorxSeoCrosslinks.config.enable')) {
$request = $this->requestStack->getMainRequest();
if ($request) {
$route = $request->attributes->get('_route');
$landingPageId = $request->attributes->get('landingPageId');
if ($route === 'frontend.landing.page' && $landingPageId) {
return true;
}
}
}
return false;
}
/**
* @param string $content
* @param string $entityId
* @param Context $context
* @param int $maxCount
* @return false|string
*/
protected function getModifiedContent(
string $content,
string $entityId,
Context $context,
int $maxCount
) {
$criteria = new Criteria();
$criteria->addFilter(
new EqualsFilter('isActive', true),
new EqualsFilter('inCmsPage', true),
new EqualsFilter('languageId', $context->getLanguageId()),
new EqualsFilter(
'salesChannels.salesChannelId',
$this->salesChannelContextProvider->getSalesChannelContext($context)->getSalesChannelId()
),
new NotFilter('AND', [
new EqualsFilter('internalLink', $entityId),
]),
);
$criteria->addSorting(new FieldSorting('priority', 'DESC'));
$crosslinkCollection = $this->crosslinkRepository->search($criteria, $context)->getEntities();
return $this->replacer->replace($context, $crosslinkCollection, $content, $maxCount);
}
}