<?php declare(strict_types=1);
namespace Cbax\ModulManufacturers\Controller;
use Shopware\Core\Framework\Context;
use Shopware\Storefront\Controller\StorefrontController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Content\Product\SalesChannel\Listing\AbstractProductListingRoute;
use Shopware\Storefront\Framework\Routing\RequestTransformer;
use Cbax\ModulManufacturers\Components\ManufacturersHelper;
use Cbax\ModulManufacturers\Components\ManufacturerSeo;
use Cbax\ModulManufacturers\Components\ManufacturersPage;
use Shopware\Storefront\Page\GenericPageLoaderInterface;
use Shopware\Core\PlatformRequest;
use Shopware\Core\Content\Cms\Aggregate\CmsBlock\CmsBlockEntity;
use Shopware\Core\Content\Cms\Aggregate\CmsSection\CmsSectionEntity;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\CmsPageEntity;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
use Shopware\Core\Content\Product\Aggregate\ProductManufacturer\ProductManufacturerDefinition;
use Shopware\Core\Content\Product\Aggregate\ProductManufacturer\ProductManufacturerEntity;
/**
* @RouteScope(scopes={"storefront"})
*/
class FrontendController extends StorefrontController
{
private AbstractProductListingRoute $listingRoute;
private ProductManufacturerDefinition $manufacturerDefinition;
private $helperComponent;
private $manufacturerSeo;
private $manufacturerRepository;
private $genericLoader;
private $mediaRepository;
private $systemConfigService;
public function __construct(
ManufacturersHelper $helperComponent,
ManufacturerSeo $manufacturerSeo,
EntityRepositoryInterface $manufacturerRepository,
GenericPageLoaderInterface $genericLoader,
EntityRepositoryInterface $mediaRepository,
SystemConfigService $systemConfigService,
AbstractProductListingRoute $listingRoute,
ProductManufacturerDefinition $manufacturerDefinition
)
{
$this->helperComponent = $helperComponent;
$this->manufacturerSeo = $manufacturerSeo;
$this->manufacturerRepository = $manufacturerRepository;
$this->genericLoader = $genericLoader;
$this->mediaRepository = $mediaRepository;
$this->systemConfigService = $systemConfigService;
$this->listingRoute = $listingRoute;
$this->manufacturerDefinition = $manufacturerDefinition;
}
/**
* @HttpCache()
* alle Daten für die Herstellerübersicht holen und aufbereiten
* @param $request Request aktueller Request
* @param $context Context Standardcontext Object
* @return Object View mit Herstellerübersicht
* @Route("/cbax/manufacturer/index", name="frontend.cbax.manufacturer.index", options={"seo"=true}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
*/
public function getManufacturers(Request $request, Context $context): Response
{
$salesChannelContext = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);
$salesChannelId = $salesChannelContext->getSalesChannelId();
$languageId = $salesChannelContext->getSalesChannel()->getLanguageId();
$shopUrl = $request->attributes->get(RequestTransformer::STOREFRONT_URL);
$config = $this->systemConfigService->get('CbaxModulManufacturers', $salesChannelId)['config'];
if ($config['active'] !== true || empty($config['cmsPageIndex'])) {
return $this->forwardToRoute('frontend.home.page');
}
// Standard Page Object für Breadcrumb erzeugen
$newPage = $this->genericLoader->load($request, $salesChannelContext);
$page = ManufacturersPage::createFrom($newPage);
$cmsPage = $this->helperComponent->getCmsPage($config['cmsPageIndex'], $context);
if ($cmsPage)
{
if ($cmsPage->getSections())
{
$cmsPage->getSections()->sort(function (CmsSectionEntity $a, CmsSectionEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
$resolverContext = new ResolverContext($salesChannelContext, $request);
// sort blocks into sectionPositions
foreach ($cmsPage->getSections() as $section) {
$section->getBlocks()->sort(function (CmsBlockEntity $a, CmsBlockEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
}
// find config overwrite
//$overwrite = $config[$page->getId()] ?? $config;
// overwrite slot config
//$this->overwriteSlotConfig($page, $overwrite);
// resolve slot data
$this->helperComponent->loadSlotData($cmsPage, $resolverContext);
}
$page->setCmsPage($cmsPage);
}
// Herstellerdaten aufbereiten
$pageData = $this->helperComponent->getManufacturerByChar($config, $salesChannelContext, $context, true);
$cbaxModulManufacturers['data'] = $pageData['sortedData'];
$cbaxModulManufacturers['page'] = 'index';
$link_index = $this->manufacturerSeo->getSeoUrl('frontend.cbax.manufacturer.index', '/cbax/manufacturer/index', $salesChannelId, $languageId, $shopUrl);
$breadcrumbLinkName = $this->container->get('translator')->trans('cbaxManufacturer.page.breadcrumb.allManufacturers');
$breadcrumb[] = array(
'link' => $link_index,
'name' => $breadcrumbLinkName,
'active' => true,
'translated' => array(
'name' => $breadcrumbLinkName
)
);
//Blöcke mit leeren Elementen nicht laden
$page = $this->helperComponent->filterEmptyCmsBlocksIndex($page, $cbaxModulManufacturers);
return $this->renderStorefront('@Storefront/storefront/base.html.twig', [
'cbaxModulManufacturers' => $cbaxModulManufacturers,
'page' => $page,
'breadcrumbList' => $breadcrumb
]);
}
/**
* @HttpCache()
* alle Daten für die Herstellerdetailseite holen und aufbereiten
* @param $request Request aktueller Request
* @param $context Context Standardcontext Object
* @return Object View mit Herstellerdetailseite
* @Route("/cbax/manufacturer/detail/{cbaxManufacturerId?}", name="frontend.cbax.manufacturer.detail", options={"seo"=true}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
*/
public function getManufacturer(Request $request, Context $context): Response
{
$salesChannelContext = $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);
$salesChannelId = $salesChannelContext->getSalesChannelId();
$languageId = $salesChannelContext->getSalesChannel()->getLanguageId();
$shopUrl = $request->attributes->get(RequestTransformer::STOREFRONT_URL);
$config = $this->systemConfigService->get('CbaxModulManufacturers', $salesChannelId)['config'];
$manufacturerId = $request->get('cbaxManufacturerId');
$pageNumber = $request->get('p');
// Checken, ob der Shopware Cache anfragt
if (empty($manufacturerId)) {
$manufacturerId = $request->get('cbaxManufacturerId');
if (empty($manufacturerId)) {
return $this->forwardToRoute('frontend.home.page');
}
}
// einzelnen Hersteller mit Bildern und Produkten holen
$criteria = new Criteria();
$criteria->addAssociation('media');
$criteria->addFilter(new EqualsFilter('id', $manufacturerId));
/** @var $data ProductManufacturerEntity|null */
$data = $this->manufacturerRepository->search($criteria, $context)->first();
if (empty($data)) {
return $this->forwardToRoute('frontend.home.page');
}
$cmsConfigPageId = !empty($config['cmsPageDetail']) ? $config['cmsPageDetail'] : null;
$cmsAltPageId = (!empty($data->getTranslated()) && !empty($data->getTranslated()['customFields']) && !empty($data->getTranslated()['customFields']['cbaxManufacturerAltCmsPage'])) ? $data->getTranslated()['customFields']['cbaxManufacturerAltCmsPage'] : null;
$cmsPageId = !empty($cmsAltPageId) ? $cmsAltPageId : $cmsConfigPageId;
if ($config['active'] !== true || empty($cmsPageId)) {
return $this->forwardToRoute('frontend.home.page');
}
if (!empty($data->getTranslated()) && !empty($data->getTranslated()['customFields']) && !empty($data->getTranslated()['customFields']['cbaxManufacturerBannerMedia'])) {
$mediaCriteria = new Criteria();
$mediaCriteria->addFilter(new EqualsFilter('id', $data->getTranslated()['customFields']['cbaxManufacturerBannerMedia']));
$bannerMedia = $this->mediaRepository->search($mediaCriteria, $context)->first();
}
// Standard Page Object für Breadcrumb erzeugen
$newPage = $this->genericLoader->load($request, $salesChannelContext);
$page = ManufacturersPage::createFrom($newPage);
/** @var $cmsPage CmsPageEntity|null **/
$cmsPage = $this->helperComponent->getCmsPage($cmsPageId, $context);
$hasSidebarFilterBlock = false;
if ($cmsPage)
{
if ($cmsPage->getSections())
{
$cmsPage->getSections()->sort(function (CmsSectionEntity $a, CmsSectionEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
$resolverContext = new EntityResolverContext($salesChannelContext, $request, $this->manufacturerDefinition, $data);
// sort blocks into sectionPositions
foreach ($cmsPage->getSections() as $section) {
$section->getBlocks()->sort(function (CmsBlockEntity $a, CmsBlockEntity $b) {
return $a->getPosition() <=> $b->getPosition();
});
}
// find config overwrite
//$overwrite = $config[$page->getId()] ?? $config;
// overwrite slot config
//$this->overwriteSlotConfig($page, $overwrite);
// resolve slot data
$this->helperComponent->loadSlotData($cmsPage, $resolverContext);
}
// suche nach sidebar filter
$filterElement = $cmsPage->getFirstElementOfType('cbax-manufacturers-filter-button');
if (!empty($filterElement))
{
$hasSidebarFilterBlock = true;
}
// suche nach sw product-listing
/** @var $swListingElement CmsSlotEntity|null **/
$swListingElement = $cmsPage->getFirstElementOfType('product-listing');
// sidebar-filter block entfernen, wenn keine Produkte im Listing
if (!empty($cmsPage->getSections()) &&
!empty($swListingElement) &&
!empty($swListingElement->getData()) &&
!empty($swListingElement->getData()->getListing()) &&
$swListingElement->getData()->getListing()->getTotal() == 0
) {
/** @var $sidebarFilter CmsSlotEntity|null **/
$sidebarFilter = $cmsPage->getFirstElementOfType('sidebar-filter');
if (!empty($sidebarFilter)) {
$sidebarFilterBlockId = $sidebarFilter->getBlockId() ?? null;
if (!empty($sidebarFilterBlockId)) {
foreach ($cmsPage->getSections() as $section) {
if (!empty($section->getBlocks())) {
$section->getBlocks()->filterAndReduceByProperty('id', $sidebarFilterBlockId);
}
}
}
}
}
$page->setCmsPage($cmsPage);
}
if ($hasSidebarFilterBlock) {
// alle Hersteller für Sidebar laden
$result = $this->helperComponent->getManufacturerByChar($config, $salesChannelContext, $context);
$cbaxModulManufacturers['data'] = $result;
}
//Produktlistendaten holen, wenn eigenes Listing, bei SW Listing kommen Daten über SW Resolver
if (empty($swListingElement))
{
// Produktlistendaten ermitteln
$data2 = $this->helperComponent->getProductsListing($manufacturerId, $pageNumber, $salesChannelContext);
if ($pageNumber > 0) {
$limit = $this->systemConfigService->get("core.listing.productsPerPage", $salesChannelId);
$limit = !empty($limit) ? (int)$limit : 20;
$offset = $limit * ($pageNumber -1);
$cbaxModulManufacturers['offset'] = $offset;
}
$cbaxModulManufacturers['products'] = $data2;
}
$cbaxModulManufacturers['manufacturer'] = $data;
if (!empty($bannerMedia) && !empty($bannerMedia->getUrl())) {
$cbaxModulManufacturers['bannerMedia'] = $bannerMedia;
}
$cbaxModulManufacturers['p'] = $pageNumber;
$cbaxModulManufacturers['page'] = 'detail';
$link_index = $this->manufacturerSeo->getSeoUrl('frontend.cbax.manufacturer.index', '/cbax/manufacturer/index', $salesChannelId, $languageId, $shopUrl);
$link_detail = $this->manufacturerSeo->getSeoUrl('frontend.cbax.manufacturer.detail', '/cbax/manufacturer/detail/' . $manufacturerId, $salesChannelId, $languageId, $shopUrl);
$breadcrumbLinkName = $this->container->get('translator')->trans('cbaxManufacturer.page.breadcrumb.allManufacturers');
$breadcrumb[] = array(
'link' => $link_index,
'name' => $breadcrumbLinkName,
'translated' => array(
'name' => $breadcrumbLinkName
)
);
$breadcrumb[] = array(
'link' => $link_detail,
'name' => $cbaxModulManufacturers['manufacturer']->getName(),
'active' => true,
'translated' => array(
'name' => $cbaxModulManufacturers['manufacturer']->getTranslated()['name']
)
);
//Blöcke mit leeren Elementen nicht laden
$page = $this->helperComponent->filterEmptyCmsBlocksDetail($page, $cbaxModulManufacturers);
return $this->renderStorefront('@Storefront/storefront/base.html.twig', [
'cbaxModulManufacturers' => $cbaxModulManufacturers,
'page' => $page,
'breadcrumbList' => $breadcrumb
]);
}
/**
* @HttpCache()
*
* Route to load the listing filters
*
* @Route("/widgets/cbax/manufacturer/{cbaxManufacturerId}/filter", name="frontend.cbax.manufacturer.filter", methods={"GET", "POST"}, defaults={"XmlHttpRequest"=true, "_routeScope"={"storefront"}})
*/
public function filter(string $cbaxManufacturerId, Request $request, SalesChannelContext $context): Response
{
$navigationId = $context->getSalesChannel()->getNavigationCategoryId();
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('manufacturerId', $cbaxManufacturerId));
// Allows to fetch only aggregations over the gateway.
$request->request->set('only-aggregations', true);
$request->request->set('manufacturer-filter', false);
// Allows to convert all post-filters to filters. This leads to the fact that only aggregation values are returned, which are combinable with the previous applied filters.
$request->request->set('reduce-aggregations', true);
$listing = $this->listingRoute
->load($navigationId, $request, $context, $criteria)
->getResult();
$mapped = [];
foreach ($listing->getAggregations() as $aggregation) {
$mapped[$aggregation->getName()] = $aggregation;
}
$response = new JsonResponse($mapped);
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, '1');
$response->headers->set('x-robots-tag', 'noindex');
return $response;
}
}