<?php declare(strict_types=1);
namespace ThemeOkeOnline\Storefront\Product\Subscriber;
use Psr\Log\LoggerInterface;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\ProductCollection;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\Adapter\Cache\CacheCompressor;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use ThemeOkeOnline\Core\Content\Product\ProductSiblingService;
class StorefrontProductSearchResultLoadedSubscriber implements EventSubscriberInterface
{
/**
* @var ProductSiblingService
*/
private $productSiblingService;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var Context
*/
private $context;
/**
* @var string
*/
public $commonPropertyGroupId;
public function __construct(
ProductSiblingService $productSiblingService,
SystemConfigService $systemConfigService
)
{
$this->productSiblingService = $productSiblingService;
$this->systemConfigService = $systemConfigService;
$this->commonPropertyGroupId = $this->systemConfigService->get('ThemeOkeOnline.config.parentProperty') ?? null;
}
public static function getSubscribedEvents(): array
{
// ProductListingCriteriaEvent::class => ['addPropertiesToProductListingCriteria'],
return [
'sales_channel.product.process.criteria' => ['addPropertiesToProductListingCriteria'],
'sales_channel.product.search.result.loaded' => ['productListingLoaded']
];
}
public function addPropertiesToProductListingCriteria($event): void
{
if( $this->commonPropertyGroupId )
{
$criteria = $event->getCriteria();
$criteria->addAssociation('options');
$criteria->addAssociation('properties');
}
}
public function productListingLoaded(EntitySearchResultLoadedEvent $event): void
{
$this->context = $event->getContext();
// Stop when settings are missing
if(!$this->commonPropertyGroupId)
return;
// Collect a list with all used property-connections
$loadedProducts = $event->getResult()->getElements();
foreach($loadedProducts as $product)
{
// Get the propertyGroupOptionIds based on the setting which defines the common-PropertyGroup
$commonPropertyGroupOptionIds = $this->getCommonPropertyGroupOptionIds($product, $this->commonPropertyGroupId);
// Get the siblings, and remove current product from list of siblings.
$data = $this->productSiblingService->getSiblingsForProduct($product, $this->context);
$product->addExtension('siblings', $data);
// Old implementation
// $siblings = $this->getSiblingsOfProduct($product, $commonPropertyGroupOptionIds, true);
// $product->addExtension('siblings', $siblings);
// Removal of 'selected' sibling. this feature has been permanently disabled
//$siblings = $this->without($siblings, $product->getId());
}
}
private function getCommonPropertyGroupOptionIds(ProductEntity $product, $commonPropertyGroupId): array
{
// Get the properties from the product, this can be null or an empty array, if so, we can return an empty array
$commonProductPropertyGroupOptions = $product->getProperties();
if( !$commonProductPropertyGroupOptions)
return [];
$commonProductPropertyGroupOptionValues = $commonProductPropertyGroupOptions->filterByGroupId($commonPropertyGroupId);
if( $commonProductPropertyGroupOptionValues->count() == 0 )
return [];
// eventually, return the ids as an array
return $commonProductPropertyGroupOptionValues->getIds();
}
// Has been replaced by productSiblingService: remove soon
// private function getSiblingsOfProduct(ProductEntity $product, array $commonPropertyGroupOptionIds): ProductCollection
// {
// if( !count($commonPropertyGroupOptionIds) > 0 )
// {
// $result = new ProductCollection();
// //$item = CacheCompressor::compress($item, $result);
// //$this->cache->save($item);
// return $result;
// }
// // We have commonPropertyGroupOptionIds, so we should query them, to find any siblings
// $criteria = new Criteria();
// $criteria->setTitle('load-siblings');
// $criteria->resetAssociations();
// $criteria->addAssociation('cover');
// $criteria->addAssociation('seoUrls');
// // Create a multi-filter, because the product we're checking could have more than one common-propertyGroupOptions (it is a multi-select in back-office)
// $multiFilter = [];
// foreach($commonPropertyGroupOptionIds as $commonPropertyGroupOptionId)
// {
// $multiFilter[] = new EqualsFilter('properties.id', $commonPropertyGroupOptionId);
// }
// $criteria->addFilter(
// new MultiFilter(
// MultiFilter::CONNECTION_OR,
// $multiFilter
// )
// );
// //Filter by options
// $productOptionsKeyValue = $this->mapToKeyValue($product->getOptions());
// $persistentOptions = $this->systemConfigService->get('ThemeOkeOnline.config.persistentOptions');
// 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])
// );
// }
// // query it!
// $result = $this->productRepository->search($criteria, $this->getContext());
// // fallback, empty product Collection
// return new ProductCollection();
// }
// 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;
// }
// ToDo: Remove soon
// private function without(ProductCollection $collection, $id): ProductCollection
// {
// $collection->remove($id);
// return $collection;
// }
private function getContext(): ?Context
{
return $this->context;
}
}