<?php
declare(strict_types=1);
namespace BDL\CustomThemeChanges\Subscriber;
use Shopware\Core\Content\Category\CategoryCollection;
use Shopware\Core\Content\Media\MediaCollection;
use Shopware\Core\Content\Product\ProductCollection;
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\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SalesChannel\SalesChannelEntity;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Shopware\Core\System\SystemConfig\SystemConfigService;
class StorefrontSubscriber implements EventSubscriberInterface
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var EntityRepositoryInterface
*/
private $productRepo;
private $categoryRepository;
private $mediaRepository;
/**
* @var SystemConfigService
*/
private $config;
public function __construct(
ContainerInterface $container,
EntityRepositoryInterface $categoryRepository,
EntityRepositoryInterface $productRepo,
EntityRepositoryInterface $mediaRepository,
SystemConfigService $config
) {
$this->container = $container;
$this->categoryRepository = $categoryRepository;
$this->productRepo = $productRepo;
$this->mediaRepository = $mediaRepository;
$this->config = $config;
}
public static function getSubscribedEvents(): array
{
return [
StorefrontRenderEvent::class => 'onStorefrontRender',
ProductPageLoadedEvent::class => 'onLoadProductPage',
];
}
public function onStorefrontRender(StorefrontRenderEvent $event)
{
$categories = [];
$salesChannelContext = $event->getSalesChannelContext();
$params = $event->getParameters();
$request = $event->getRequest();
$context = $event->getContext();
$salesChannelEntity = $salesChannelContext->getSalesChannel();
$footerMenuId = $salesChannelEntity->getFooterCategoryId();
$headerContactMenuId = $salesChannelEntity->getFooterCategoryId();
$customFields = $this->loadCustomFields($salesChannelEntity);
$bdlCustomFields = $salesChannelEntity->getCustomFields();
$event->setParameter('bdlCustomThemeSettings', $customFields);
$event->setParameter('bdlFooterMenu', $this->loadFooterMenu($context, $footerMenuId));
$topBarMenus = [];
if (!empty($bdlCustomFields['BDL_topbar_contact_menu']))
$topBarMenus = $this->getContactMenu($context, $bdlCustomFields['BDL_topbar_contact_menu']);
$event->setParameter('bdlTopbarContactMenu', $topBarMenus);
$event->setParameter('plugins', $this->getAllPlugins());
$route = $event->getRequest()->attributes->get('_route');
if ($route == 'frontend.detail.page') {
$params = $event->getParameters();
$product = $params['page']->getProduct();
$availableOptions = [];
if ($product->getParentId()) {
$salesChannelContext = $event->getSalesChannelContext();
$saleChannelId = $salesChannelContext->getSalesChannel()->getId();
$availableOptions = $this->getAvailableOptions($product, $saleChannelId);
$availableOptions = array_reduce($availableOptions, 'array_merge', array());
$event->setParameter('availableOptions', $availableOptions);
}
}
}
private function loadCustomFields(SalesChannelEntity $salesChannelEntity): array
{
$customFields = $salesChannelEntity->getCustomFields() ?? [];
return $customFields;
}
private function loadFooterMenu($context, $footerMenuId): CategoryCollection
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('category.active', true))
->addFilter(new EqualsFilter('category.parentId', $footerMenuId));
/** @var CategoryCollection $categories */
$categories = $this->categoryRepository->search($criteria, $context)->getEntities();
return $categories->sortByPosition();
}
private function getContactMenu($context, $headerMenuId): CategoryCollection
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('category.active', true))
->addFilter(new EqualsAnyFilter('category.id', $headerMenuId));
/** @var CategoryCollection $categories */
$categories = $this->categoryRepository->search($criteria, $context)->getEntities();
return $categories->sortByPosition();
}
public function searchCategory(array $ids, Context $context): CategoryCollection
{
if (empty($ids)) {
return new CategoryCollection();
}
$criteria = new Criteria($ids);
/** @var CategoryCollection $product */
$category = $this->categoryRepository
->search($criteria, $context)
->getEntities();
return $category;
}
private function getAllPlugins()
{
$pluginRepo = $this->container->get('plugin.repository');
$criteria = (new Criteria());
$plugins = $pluginRepo->search($criteria, Context::createDefaultContext())->getEntities();
$pluginsArray = [];
if (!empty($plugins)) {
foreach ($plugins as $plugin) {
$pluginsArray[$plugin->getName()] = $plugin;
}
}
return ($pluginsArray) ? $pluginsArray : null;
}
public function onLoadProductPage(ProductPageLoadedEvent $event)
{
$salesChannelContext = $event->getSalesChannelContext();
$saleChannelId = $salesChannelContext->getSalesChannel()->getId();
$product = $event->getPage()->getProduct();
$grossPrice = [];
if (empty($product->getPrices()->first()))
$grossPrice = $product->getPrice()->first();
$grossPriceSalesChannels = $this->config->get('BDLCustomThemeChanges.config.grossPriceSalesChannels');
$product->setExtensions([
'salesChannelId' => $saleChannelId,
'grossPriceSalesChannels' => $grossPriceSalesChannels,
'enableGrossPriceInDetailedPage' => in_array($saleChannelId, $grossPriceSalesChannels) ? 1 : 0,
'grossPriceData' => $grossPrice
]);
}
public function getAvailableOptions($product, $saleChannelId)
{
$productRepository = $this->container->get('product.repository');
$criteria = new Criteria([]);
$criteria->addFilter(new EqualsFilter('parentId', $product->getParentId()));
$criteria->addAssociation('entities.visibilities');
/** @var ProductEntity $product */
$parentProduct = $productRepository->search($criteria, Context::createDefaultContext())->getEntities();
$activeOptions = [];
foreach ($parentProduct->getElements() as $prodOption) {
$activeOptions[] = $this->getVisibility($prodOption->getId(), $saleChannelId);
}
return $activeOptions;
}
public function getVisibility($productId, $saleChannelId)
{
$productRepository = $this->container->get('product.repository');
$criteria = new Criteria([$productId]);
$criteria->addAssociation('visibilities');
$criteria->addAssociation('options');
/** @var ProductEntity $product */
$productEntity = $productRepository->search($criteria, Context::createDefaultContext())->first();
$prodIds = [];
foreach ($productEntity->getVisibilities()->getElements() as $entity) {
if ($entity->getSalesChannelId() == $saleChannelId && $productEntity->getActive()) {
$options = $productEntity->getOptions()->getElements();
foreach ($options as $option) {
$prodIds[] = $option->getId();
}
}
}
return $prodIds;
}
}