<?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\ProductListingCollectFilterEvent;
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\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',
ProductSearchResultEvent::class => ['onSearchResult', -10],
ProductPageLoadedEvent::class => ['onProductPageLoaded', -10],
ProductListingResultEvent::class => ['onProductListingResult', -10],
ProductListingCollectFilterEvent::class => 'onCollectFilters'
];
if (class_exists('\Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent')) {
/** @phpstan-ignore-next-line */
$events[\Acris\Search\Core\Content\Product\Events\ProductManufacturerResultEvent::class]
= 'onAcrisProductManufacturerResultEvent';
}
if (class_exists('\Acris\SuggestedProducts\Storefront\Page\RecentlyViewed\RecentlyViewedPageLoadedEvent')) {
/** @phpstan-ignore-next-line */
$events[\Acris\SuggestedProducts\Storefront\Page\RecentlyViewed\RecentlyViewedPageLoadedEvent::class]
= 'onAcrisRecentlyViewedPageLoadedEvent';
}
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 onCollectFilters(ProductListingCollectFilterEvent $event)
{
ListingVariantsLoader::setFilters($event->getFilters());
}
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()) {
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() || !$config->isShowInCrossSelling()) {
return;
}
// get cross selling products
$page = $event->getPage();
$crossSellings = [];
try {
if ($event->getPage()->getCrossSellings()) {
foreach ($event->getPage()->getCrossSellings()->getElements() as $element) {
$crossSellings[] = $element->getProducts()->getElements();
}
}
} catch (TypeError $e) {}
// get AcrisSuggestedProductsCS products
$extensionKeys = [
'acris_customers_also_bought',
'acris_customers_also_viewed',
'acris_recently_viewed_allowed',
'acris_recently_viewed_products',
'acrisSuggestedProducts'
];
foreach ($extensionKeys as $key) {
if ($page->getProduct()->hasExtension($key)) {
$extension = $page->getProduct()->getExtension($key);
if (!$extension) {
continue;
}
if ($extension instanceof ArrayEntity && isset($extension['products'])) {
$products = $extension['products'];
} else {
$products = $extension->getProducts();
}
if (is_array($products)) {
$crossSellings[] = $products;
} else {
$crossSellings[] = $products->getElements();
}
}
}
// load variants for all cross sellings
if ($crossSellings) {
foreach ($crossSellings as $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()) {
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());
}
}
}
/**
* AcrisSuggestedProductsCS recently viewed products
/** @phpstan-ignore-next-line */
public function onAcrisRecentlyViewedPageLoadedEvent(\Acris\SuggestedProducts\Storefront\Page\RecentlyViewed\RecentlyViewedPageLoadedEvent $event)
{
$config = $this->configService->getBaseConfig($event->getSalesChannelContext());
if ($config->isPluginEnabled() && $config->isShowInCrossSelling()) {
try {
$this->listingVariantsLoader->load($event->getPage()->getProducts(), $event->getSalesChannelContext());
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants on ProductManufacturerResultEvent: '.
$e->getMessage().",\nStack trace: ".$e->getTraceAsString());
}
}
}
}