<?php declare(strict_types=1);
namespace H1web\Blog\Storefront\Page\Blog;
use H1web\Blog\Blog\BlogDefinition;
use H1web\Blog\Blog\BlogEntity;
use H1web\Blog\Blog\SalesChannel\BlogAvailableFilter;
use H1web\Blog\Service\BlogCategoryBreadCrumbBuilder;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Content\Cms\DataResolver\CmsSlotsDataResolver;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
use Shopware\Core\Content\Cms\Exception\PageNotFoundException;
use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\GenericPageLoader;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
class BlogPageLoader
{
/**
* @var GenericPageLoader
*/
private $genericLoader;
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var CmsSlotsDataResolver
*/
private $slotDataResolver;
/**
* @var SalesChannelCmsPageRepository
*/
private $cmsPageRepository;
/**
* @var EntityRepository
*/
private $blogRepository;
/**
* @var BlogCategoryBreadCrumbBuilder
*/
private $breadCrumbBuilder;
public function __construct(
GenericPageLoader $genericLoader,
EventDispatcherInterface $eventDispatcher,
CmsSlotsDataResolver $slotDataResolver,
SalesChannelCmsPageRepository $cmsPageRepository,
EntityRepository $blogRepository,
BlogCategoryBreadCrumbBuilder $breadCrumbBuilder
) {
$this->eventDispatcher = $eventDispatcher;
$this->genericLoader = $genericLoader;
$this->slotDataResolver = $slotDataResolver;
$this->cmsPageRepository = $cmsPageRepository;
$this->blogRepository = $blogRepository;
$this->breadCrumbBuilder = $breadCrumbBuilder;
}
/**
* @throws PageNotFoundException
*/
public function load(string $blogId, Request $request, SalesChannelContext $context): BlogPage
{
try {
$page = $this->genericLoader->load($request, $context);
$page = BlogPage::createFrom($page);
$criteria = new Criteria([$blogId]);
$criteria->addFilter(new BlogAvailableFilter($context->getSalesChannelId(), $request->cookies->get("timezone")));
$criteria->addAssociation('categories')
->addAssociation('tags')
->addAssociation('customFields')
->addAssociation('properties')
->addAssociation('properties.group');
$entities = $this->blogRepository->search(
$criteria,
$context->getContext()
);
if ($entities->count() == 0) {
throw new PageNotFoundException($blogId);
}
$blog = $entities->first();
$blog->setSeoCategory($this->breadCrumbBuilder->getBlogSeoCategory($blog, $context));
$page->setBlog($blog);
$this->loadMetaData($page);
if ($cmsPage = $this->loadCmsPage($request, $context, $blog)) {
$page->setCmsPage($cmsPage);
}
$this->eventDispatcher->dispatch(new BlogPageLoadedEvent($page, $context, $request));
return $page;
} catch (\Exception $e) {
throw new PageNotFoundException($blogId);
}
}
private function loadMetaData(BlogPage $page): void
{
$metaInformation = $page->getMetaInformation();
$metaDescription = $page->getBlog()->getMetaDescription();
$metaInformation->setMetaDescription((string) $metaDescription);
$metaInformation->setMetaKeywords((string) $page->getBlog()->getKeywords());
if ((string) $page->getBlog()->getMetaTitle() !== '') {
$metaInformation->setMetaTitle((string) $page->getBlog()->getMetaTitle());
} else {
$metaInformation->setMetaTitle((string) $page->getBlog()->getTitle());
}
}
private function loadCmsPage(Request $request, SalesChannelContext $context, BlogEntity $blog): ?CmsPageEntity
{
if (!$cmsPageId = $blog->getCmsPageId()) {
return null;
}
$pages = $this->cmsPageRepository->read([$cmsPageId], $context);
if ($pages->count() === 0) {
return null;
}
/** @var CmsPageEntity $page */
$page = $pages->first();
if (!$page->getSections()) {
return null;
}
$page->getSections()->sort(function (CmsSectionEntity $a, CmsSectionEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
$resolverContext = new EntityResolverContext($context, $request, new BlogDefinition(), $blog);
// sort blocks into sectionPositions
foreach ($page->getSections() as $section) {
$section->getBlocks()->sort(function (CmsBlockEntity $a, CmsBlockEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
}
// find config overwrite
$config = $blog->getSlotConfig();
$overwrite = $config[$page->getId()] ?? $config;
// overwrite slot config
$this->overwriteSlotConfig($page, $overwrite);
// resolve slot data
$slots = $this->slotDataResolver->resolve($page->getSections()->getBlocks()->getSlots(), $resolverContext);
$page->getSections()->getBlocks()->setSlots($slots);
return $page;
}
private function overwriteSlotConfig(CmsPageEntity $page, ?array $config): void
{
foreach ($page->getSections()->getBlocks()->getSlots() as $slot) {
if ($slot->getConfig() === null && $slot->getTranslation('config') !== null) {
$slot->setConfig($slot->getTranslation('config'));
}
if (empty($config)) {
continue;
}
if (!isset($config[$slot->getId()])) {
continue;
}
$defaultConfig = $slot->getConfig() ?? [];
$merged = array_replace_recursive(
$defaultConfig,
$config[$slot->getId()]
);
$slot->setConfig($merged);
$slot->addTranslated('config', $merged);
}
}
}