<?php declare(strict_types=1);
namespace EmcgnStandardCmsPages\Core\Content\Category;
use EmcgnStandardCmsPages\Core\Exception\EmcgnConfigNotFound;
use Shopware\Core\Content\Category\CategoryDefinition;
use Shopware\Core\Content\Category\CategoryEntity;
use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
use Shopware\Core\Content\Category\SalesChannel\AbstractCategoryRoute;
use Shopware\Core\Content\Category\SalesChannel\CategoryRouteResponse;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
use Shopware\Core\Content\Cms\Exception\PageNotFoundException;
use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageLoaderInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepository;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpFoundation\Request;
class EmcgnCategoryRoute extends AbstractCategoryRoute
{
/**
* @var string
*/
public const HOME = 'home';
private SalesChannelRepository $categoryRepository;
private CategoryDefinition $categoryDefinition;
private SalesChannelCmsPageLoaderInterface $cmsPageLoader;
private SystemConfigService $config;
private EntityRepository $entityRepository;
/**
* @param SalesChannelRepository $categoryRepository
* @param CategoryDefinition $categoryDefinition
* @param SalesChannelCmsPageLoaderInterface $cmsPageLoader
* @param SystemConfigService $config
* @param EntityRepository $entityRepository
*/
public function __construct(
SalesChannelRepository $categoryRepository,
CategoryDefinition $categoryDefinition,
SalesChannelCmsPageLoaderInterface $cmsPageLoader,
SystemConfigService $config,
EntityRepository $entityRepository
)
{
$this->categoryRepository = $categoryRepository;
$this->categoryDefinition = $categoryDefinition;
$this->cmsPageLoader = $cmsPageLoader;
$this->config = $config;
$this->entityRepository = $entityRepository;
}
/**
* @return AbstractCategoryRoute
*/
public function getDecorated(): AbstractCategoryRoute
{
throw new DecorationPatternException(self::class);
}
/**
* @param string $navigationId
* @param Request $request
* @param SalesChannelContext $context
* @return CategoryRouteResponse
*/
public function load(string $navigationId, Request $request, SalesChannelContext $context): CategoryRouteResponse
{
$salesChannel = $context->getSalesChannel();
if ($navigationId === self::HOME) {
$navigationId = $salesChannel->getNavigationCategoryId();
$request->attributes->set('navigationId', $navigationId);
$routeParams = $request->attributes->get('_route_params', []);
$routeParams['navigationId'] = $navigationId;
$request->attributes->set('_route_params', $routeParams);
}
$category = $this->loadCategory($navigationId, $context);
if (($category->getType() === CategoryDefinition::TYPE_FOLDER
|| $category->getType() === CategoryDefinition::TYPE_LINK)
&& $salesChannel->getNavigationCategoryId() !== $navigationId)
{
throw new CategoryNotFoundException($navigationId);
}
$pageId = $category->getCmsPageId();
$slotConfig = $category->getTranslation('slotConfig');
if ($category->getId() === $salesChannel->getNavigationCategoryId() && $salesChannel->getHomeCmsPageId()) {
$pageId = $salesChannel->getHomeCmsPageId();
$slotConfig = $salesChannel->getTranslation('homeSlotConfig');
}
if($pageId) {
$cmsPage = $this->entityRepository->search(new Criteria([$pageId]), $context->getContext())->first();
$cmsLocked = $cmsPage->getLocked();
}
if ($pageId && $cmsLocked == false) {
$this->setCmsPage($context, $pageId, $request, $category, $slotConfig);
} else {
$pageIdConfig = $this->config->get('EmcgnStandardCmsPages.config.selectedCmsCategoryPage');
if($pageId && $cmsLocked == true) {
if(!empty($pageIdConfig)) {
$cmsPageConfig = $this->entityRepository->search(new Criteria([$pageIdConfig]), $context->getContext())->first();
if(!empty($cmsPageConfig)) {
$this->setConfigCmsPage($context, $pageIdConfig, $request, $category, $slotConfig);
} else {
$this->setCmsPage($context, $pageId, $request, $category, $slotConfig);
}
} else {
$this->setCmsPage($context, $pageId, $request, $category, $slotConfig);
}
} else {
if(!empty($pageIdConfig)) {
$cmsPageConfig = $this->entityRepository->search(new Criteria([$pageIdConfig]), $context->getContext())->first();
if(!empty($cmsPageConfig)) {
$this->setConfigCmsPage($context, $pageIdConfig, $request, $category, $slotConfig);
} else {
throw new EmcgnConfigNotFound('standard CMS category page');
}
} else {
throw new EmcgnConfigNotFound('standard CMS category page');
}
}
}
return new CategoryRouteResponse($category);
}
/**
* @param SalesChannelContext $context
* @param string $pageId
* @param Request $request
* @param CategoryEntity $category
* @param $slotConfig
* @return void
*/
private function setConfigCmsPage(SalesChannelContext $context, string $pageId, Request $request, CategoryEntity $category, $slotConfig): void
{
$cmsPage = $this->entityRepository->search(new Criteria([$pageId]), $context->getContext())->first();
if (!empty($cmsPage)) {
$cmsType = $cmsPage->getType();
if ($cmsType == 'product_list') {
$this->setCmsPage($context, $pageId, $request, $category, $slotConfig);
}
}
}
/**
* @param string $categoryId
* @param SalesChannelContext $context
* @return CategoryEntity
*/
private function loadCategory(string $categoryId, SalesChannelContext $context): CategoryEntity
{
$criteria = new Criteria([$categoryId]);
$criteria->setTitle('category::data');
$criteria->addAssociation('media');
$category = $this->categoryRepository
->search($criteria, $context)
->get($categoryId);
if (!$category) {
throw new CategoryNotFoundException($categoryId);
}
return $category;
}
/**
* @param string $pageId
* @param Request $request
* @return Criteria
*/
private function createCriteria(string $pageId, Request $request): Criteria
{
$criteria = new Criteria([$pageId]);
$criteria->setTitle('category::cms-page');
$slots = $request->get('slots');
if (is_string($slots)) {
$slots = explode('|', $slots);
}
if (!empty($slots) && is_array($slots)) {
$criteria
->getAssociation('sections.blocks')
->addFilter(new EqualsAnyFilter('slots.id', $slots));
}
return $criteria;
}
/**
* @param SalesChannelContext $context
* @param string $pageId
* @param Request $request
* @param CategoryEntity $category
* @param $slotConfig
* @return void
*/
private function setCmsPage(SalesChannelContext $context, string $pageId, Request $request, CategoryEntity $category, $slotConfig): void
{
$resolverContext = new EntityResolverContext($context, $request, $this->categoryDefinition, $category);
$pages = $this->cmsPageLoader->load(
$request,
$this->createCriteria($pageId, $request),
$context,
$slotConfig,
$resolverContext
);
if (!$pages->has($pageId)) {
throw new PageNotFoundException($pageId);
}
$category->setCmsPage($pages->get($pageId));
$category->setCmsPageId($pageId);
}
}