<?php declare(strict_types=1);
namespace Maxia\MaxiaListingVariants6\Subscriber;
use Maxia\MaxiaListingVariants6\Service\ConfigService;
use Maxia\MaxiaListingVariants6\Service\ListingVariantsLoader;
use Monolog\Logger;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Shopware\Storefront\Event\ThemeCompilerEnrichScssVariablesEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use TypeError;
/**
* @package Maxia\MaxiaListingVariants6\Subscriber
*/
class Storefront implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
$events = [
StorefrontRenderEvent::class => 'onStorefrontRender',
ThemeCompilerEnrichScssVariablesEvent::class => 'enrichScssVariables',
ProductSearchResultEvent::class => ['onSearchResult', -10],
ProductPageLoadedEvent::class => ['onProductPageLoaded', -10],
ProductListingResultEvent::class => ['onProductListingResult', -10]
];
if (class_exists('\Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent')) {
$events[\Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent::class]
= 'onAcrisProductManufacturerResultEvent';
}
return $events;
}
/**
* @var ListingVariantsLoader
*/
private $listingVariantsLoader;
/**
* @var ConfigService
*/
private $configService;
/**
* @var Logger
*/
private $logger;
public function __construct(
ListingVariantsLoader $variantListingService,
Logger $logger,
ConfigService $configService
) {
$this->listingVariantsLoader = $variantListingService;
$this->configService = $configService;
$this->logger = $logger;
}
public function enrichScssVariables(ThemeCompilerEnrichScssVariablesEvent $event)
{
$databaseUrl = getenv('DATABASE_URL');
if (!$databaseUrl || $databaseUrl === 'mysql://_placeholder.test') {
// deployment server without database
return;
}
$prefix = 'maxia-listing-variants-';
$config = $this->configService->getBaseConfig($event->getSalesChannelId());
if ($config->getBuyButtonHeight()) {
$event->addVariable($prefix . 'actions-height', $config->getBuyButtonHeight());
}
if ($config->getMediaOptionHeight()) {
$event->addVariable($prefix . 'media-option-height', $config->getMediaOptionHeight());
}
if ($config->getColorOptionHeight()) {
$event->addVariable($prefix . 'color-option-height', $config->getColorOptionHeight());
}
}
public function onStorefrontRender(StorefrontRenderEvent $event)
{
// add plugin config to context
$context = $event->getSalesChannelContext();
$config = $this->configService->getBaseConfig($context);
$context->addExtension('maxiaListingVariants', $config);
if (!$config->isPluginEnabled() || $config->getDisplayMode() === 'none') {
return;
}
$request = $event->getRequest();
// CbaxModulManufacturers: Load variants on storefront render (plugin has no result event)
if ($request->attributes->get('_route') === 'frontend.cbax.manufacturer.detail') {
try {
/** @var \Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult $products */
$products = $event->getParameters()['cbaxModulManufacturers']['products'];
if ($products && $products->getEntities() && $products->getTotal()) {
$this->listingVariantsLoader->load($products->getEntities()->getElements(), $event->getSalesChannelContext());
}
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants in cbax manufacturer listing: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
/**
* Loads variants in search results listing.
*
* @param ProductSearchResultEvent $event
*/
public function onSearchResult(ProductSearchResultEvent $event)
{
$products = $event->getResult()->getEntities();
$config = $this->configService->getBaseConfig($event->getSalesChannelContext());
if ($config->isPluginEnabled() && $config->isShowInSearchListing()) {
$disablePreselection = $config->isDisablePreselectionInSearch();
if ($event->getSalesChannelContext()->hasExtension('acris_exact_search')
&& $event->getResult()->getTotal() === 1)
{
$disablePreselection = true;
}
if ($disablePreselection) {
$event->getRequest()->attributes->set('maxia-handle-variant-preselection', false);
}
try {
$this->listingVariantsLoader->load($products->getElements(), $event->getSalesChannelContext());
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants in search result: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
/**
* Loads variants via ProductListingResultEvent
*
* @param ProductListingResultEvent $event
*/
public function onProductListingResult(ProductListingResultEvent $event)
{
$products = $event->getResult()->getEntities();
$config = $this->configService->getBaseConfig($event->getSalesChannelContext());
/** @var ArrayEntity $extension */
$extension = $event->getResult()->getExtension('maxiaListingVariants');
if ($config->isPluginEnabled() && $extension && $extension->get('loadVariants')) {
try {
$this->listingVariantsLoader->load($products->getElements(), $event->getSalesChannelContext());
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants in product listing result: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
/**
* Load variants in cross selling when no cms layout is assigned.
* Otherwise, variants will be loaded from CrossSellingCmsElementResolver
*
* @param ProductPageLoadedEvent $event
*/
public function onProductPageLoaded(ProductPageLoadedEvent $event)
{
$config = $this->configService->getBaseConfig($event->getSalesChannelContext());
if (!$config->isPluginEnabled()) {
return;
}
try {
$crossSellings = $event->getPage()->getCrossSellings();
} catch (TypeError $e) {
// @todo: remove try catch when possible
return;
}
$products = [];
if ($crossSellings && $config->isShowInCrossSelling()) {
foreach ($crossSellings as $crossSelling) {
if ($crossSelling->getProducts()) {
foreach ($crossSelling->getProducts()->getElements() as $product) {
$products[] = $product;
}
}
}
}
if ($products) {
try {
$this->listingVariantsLoader->load($products, $event->getSalesChannelContext());
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants in cross selling: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
/**
* AcrisSearchCS manufacturer product listing
*
* @param \Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent $event
*/
/** @phpstan-ignore-next-line */
public function onAcrisProductManufacturerResultEvent(\Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent $event)
{
$products = $event->getResult()->getEntities();
$config = $this->configService->getBaseConfig($event->getSalesChannelContext());
if ($config->isPluginEnabled() && $config->getDisplayMode() !== 'none') {
try {
$this->listingVariantsLoader->load($products->getElements(), $event->getSalesChannelContext());
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants on ProductManufacturerResultEvent: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
}