<?php declare(strict_types=1);
namespace DreiscSet\Subscriber\DataAbstractionLayer;
use DreiscSet\Core\Cache\AbstractCacheInvalidator;
use DreiscSet\Core\Content\DreiscSetGroup\DreiscSetGroupRepository;
use DreiscSet\Core\Content\DreiscSetGroupItem\DreiscSetGroupItemRepository;
use DreiscSet\Core\Content\Product\ProductRepository;
use DreiscSet\Core\Content\ProductStream\ProductStreamRepository;
use Shopware\Core\Content\ProductStream\Service\ProductStreamBuilder;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\Context;
class ProductWrittenSubscriber implements EventSubscriberInterface
{
/**
* @var DreiscSetGroupItemRepository
*/
protected $dreiscSetGroupItemRepository;
/**
* @var AbstractCacheInvalidator
*/
protected $cacheInvalidator;
/**
* @var ProductStreamRepository
*/
protected $productStreamRepository;
/**
* @var ProductStreamBuilder
*/
protected $productStreamBuilder;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var DreiscSetGroupRepository
*/
protected $dreiscSetGroupRepository;
/**
* @param DreiscSetGroupItemRepository $dreiscSetGroupItemRepository
* @param AbstractCacheInvalidator $cacheInvalidator
* @param ProductStreamRepository $productStreamRepository
* @param ProductStreamBuilder $productStreamBuilder
* @param ProductRepository $productRepository
* @param DreiscSetGroupRepository $dreiscSetGroupRepository
*/
public function __construct(DreiscSetGroupItemRepository $dreiscSetGroupItemRepository, AbstractCacheInvalidator $cacheInvalidator, ProductStreamRepository $productStreamRepository, ProductStreamBuilder $productStreamBuilder, ProductRepository $productRepository, DreiscSetGroupRepository $dreiscSetGroupRepository)
{
$this->dreiscSetGroupItemRepository = $dreiscSetGroupItemRepository;
$this->cacheInvalidator = $cacheInvalidator;
$this->productStreamRepository = $productStreamRepository;
$this->productStreamBuilder = $productStreamBuilder;
$this->productRepository = $productRepository;
$this->dreiscSetGroupRepository = $dreiscSetGroupRepository;
}
public static function getSubscribedEvents()
{
return [
'product.written' => 'onProductWritten'
];
}
public function onProductWritten(EntityWrittenEvent $entityWrittenEvent)
{
$invalideDreiscSetIds = [];
/** Determine invalid sets based on direct product assignments to the set group */
$invalideDreiscSetIds = array_merge($this->determineDirectAssignments($entityWrittenEvent->getIds()), $invalideDreiscSetIds);
/** Determine invalid sets based on product stream assignments to the set group */
$invalideDreiscSetIds = array_merge($this->determineProductStreamAssignments($entityWrittenEvent->getIds()), $invalideDreiscSetIds);
$this->cacheInvalidator->invalidateSetParentProducts($invalideDreiscSetIds);
}
/**
* @param array $productIds
* @return array
*/
private function determineDirectAssignments(array $productIds): array
{
$invalideDreiscSetIds = [];
/** Fetch all sets with the products are assigned to */
$criteria = (new Criteria())
->addFilter(
new EqualsAnyFilter('productId', $productIds)
)
->addAssociation('dreiscSetGroup');
$entitySearchResult = $this->dreiscSetGroupItemRepository->search($criteria);
/** Abort, if no match was found */
if (0 === $entitySearchResult->count()) {
return $invalideDreiscSetIds;
}
/** Fetch the dreisc set ids which we need to invalidate */
foreach($entitySearchResult->getEntities() as $dreiscSetGroupItemEntity ) {
$invalideDreiscSetIds[] = $dreiscSetGroupItemEntity->getDreiscSetGroup()->getDreiscSetId();
}
return $invalideDreiscSetIds;
}
/**
* @param array $productIds
* @return array
*/
private function determineProductStreamAssignments(array $productIds): array
{
$invalideProductStreamIds = $this->fetchProductStreamIdsWithProducts($productIds);
$invalideDreiscSetIds = [];
/** Fetch all sets with the products are assigned to */
$criteria = (new Criteria())
->addFilter(
new EqualsAnyFilter('productStreamId', $invalideProductStreamIds)
);
$entitySearchResult = $this->dreiscSetGroupRepository->search($criteria);
/** Abort, if no match was found */
if (0 === $entitySearchResult->count()) {
return $invalideDreiscSetIds;
}
/** Fetch the dreisc set ids which we need to invalidate */
foreach($entitySearchResult->getEntities() as $dreiscSetGroupEntity ) {
$invalideDreiscSetIds[] = $dreiscSetGroupEntity->getDreiscSetId();
}
return $invalideDreiscSetIds;
}
/**
* @param array $productIds
* @return array
*/
private function fetchProductStreamIdsWithProducts(array $productIds): array
{
$invalideProductStreamIds = [];
/** At first, we iterate all product streams to check, if one of the given products is part of it */
$idSearchResult = $this->productStreamRepository->searchIds(new Criteria());
foreach ($idSearchResult->getIds() as $productStreamId) {
/** Build the product stream filters */
$productStreamFilters = $this->productStreamBuilder->buildFilters($productStreamId, Context::createDefaultContext());
/** Create a criteria with the product stream filters and the products ids */
$criteria = (new Criteria())->addFilter(
new MultiFilter(MultiFilter::CONNECTION_AND, [
...$productStreamFilters,
new EqualsAnyFilter('product.id', $productIds)
])
);
if (!empty($this->productRepository->searchIds($criteria)->getIds())) {
$invalideProductStreamIds[] = $productStreamId;
}
}
return $invalideProductStreamIds;
}
}