<?php declare(strict_types=1);
namespace ThemeOkeOnline\Storefront\Page\Product;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Content\Product\Exception\ReviewNotActiveExeption;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Product\ProductLoaderCriteriaEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ProductPageLoadedEventSubscriber implements EventSubscriberInterface
{
/**
* @var ProductPageLoadedEvent
*/
private $event;
private $context;
private $page;
private $request;
/**
* @var EntityRepository
*/
private $productRepository;
/**
* @var EntityRepository
*/
private $propertyGroupRepository;
/**
* @var EntityRepository
*/
private $propertyGroupOptionRepository;
/**
* @var ProductReviewLoader
*/
private $productReviewLoader;
/**
* @var SystemConfigService
*/
private $systemConfigService;
public function __construct(
EntityRepository $productRepository,
EntityRepository $propertyGroupRepository,
EntityRepository $propertyGroupOptionRepository,
ProductReviewLoader $productReviewLoader,
SystemConfigService $systemConfigService
)
{
$this->productRepository = $productRepository;
$this->propertyGroupRepository = $propertyGroupRepository;
$this->propertyGroupOptionRepository = $propertyGroupOptionRepository;
$this->productReviewLoader = $productReviewLoader;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
'Shopware\Storefront\Page\Product\ProductPageLoadedEvent' => ['productLoaded']
];
}
public function productLoaded(ProductPageLoadedEvent $event): void
{
$this->addReviewDataToProductPage($event);
$this->addSiblingDataToProductPage($event);
}
private function mapToKeyValue($items){
$keyValue = [];
foreach ($items as $item) {
$key = $item->getGroupId();
$value = $item->getId();
if(!array_key_exists($key, $keyValue))
$keyValue[$key] = [];
$keyValue[$key][] = $value;
}
return $keyValue;
}
public function addSiblingDataToProductPage(ProductPageLoadedEvent $event): void
{
$this->event = $event;
$context = $event->getContext();
$page = $event->getPage();
$product = $page->getProduct();
$configuratorSettings = $page->getConfiguratorSettings();
//Config variables
$parentProperty = $this->systemConfigService->get('ThemeOkeOnline.config.parentProperty'); //String
$persistentOptions = $this->systemConfigService->get('ThemeOkeOnline.config.persistentOptions'); //Array with strings
//Show warning on top of page when missing config
if($parentProperty == null || $persistentOptions == null)
return;
//Create key-value arrays for easy reference
$productOptionsKeyValue = $this->mapToKeyValue($product->getOptions());
$productPropertiesKeyValue = $this->mapToKeyValue($product->getProperties());
//Stop when the product does not have the required properties
if(sizeof($productPropertiesKeyValue) == 0 || !array_key_exists($parentProperty, $productPropertiesKeyValue))
return;
//Search for siblings
$criteria = new Criteria();
$criteria->addAssociation('name');
$criteria->addAssociation('properties');
$criteria->addAssociation('options');
$criteria->addAssociation('cover');
$criteria->addFilter(
new EqualsFilter('properties.id', $productPropertiesKeyValue[$parentProperty][0])
);
if(sizeof($productOptionsKeyValue) > 0) foreach($persistentOptions as $option){
$criteria->addFilter(
//Always take first value of this option (no multi-selects)
new EqualsFilter('options.id', $productOptionsKeyValue[$option][0])
);
}
$data = $this->productRepository->search($criteria, $context);
$page->addExtension('siblings', $data);
return;
}
/*
* Somehow the reviews are not available when using our plugin, but we will get them back!
*/
public function addReviewDataToProductPage($event): void
{
$this->event = $event;
$this->context = $event->getSalesChannelContext();
$this->page = $event->getPage();
$this->request = $event->getRequest();
$this->checkReviewsActive();
$reviews = $this->getProductReviews();
$this->page->addExtension('reviews', $reviews);
}
private function getProductReviews(): Object
{
$product = $this->page->getProduct();
$reviews = $this->productReviewLoader->load($this->request, $this->context);
$reviews->setParentId($product->getParentId() ?? $product->getId());
return $reviews;
}
/**
* @throws ReviewNotActiveExeption
*/
private function checkReviewsActive(): void
{
$showReview = $this->systemConfigService->get('core.listing.showReview', $this->context->getSalesChannel()->getId());
if (!$showReview) {
throw new ReviewNotActiveExeption();
}
}
}