<?php declare(strict_types=1);
namespace Acris\DiscountGroup\Storefront\Subscriber;
use Acris\DiscountGroup\Custom\DiscountGroupDefinition;
use Acris\DiscountGroup\Custom\DiscountGroupEntity;
use Shopware\Core\Content\Product\Aggregate\ProductPrice\ProductPriceEntity;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Content\Product\SalesChannel\Detail\CachedProductDetailRoute;
use Shopware\Core\Framework\Adapter\Cache\CacheInvalidator;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class DiscountGroupSubscriber implements EventSubscriberInterface
{
const DISCOUNT_GROUP_WRITTEN_EVENT = 'acris_discount_group.written';
private EntityRepositoryInterface $discountGroupRepository;
private EntityRepositoryInterface $productRepository;
private EntityRepositoryInterface $productStreamMappingRepository;
private CacheInvalidator $logger;
public function __construct(
EntityRepositoryInterface $discountGroupRepository, EntityRepositoryInterface $productRepository, EntityRepositoryInterface $productStreamMappingRepository, CacheInvalidator $logger
) {
$this->discountGroupRepository = $discountGroupRepository;
$this->productRepository = $productRepository;
$this->productStreamMappingRepository = $productStreamMappingRepository;
$this->logger = $logger;
}
public static function getSubscribedEvents(): array
{
return [
self::DISCOUNT_GROUP_WRITTEN_EVENT => 'onDiscountGroupWritten',
ProductEvents::PRODUCT_LOADED_EVENT => 'onProductLoaded'
];
}
public function onProductLoaded(EntityLoadedEvent $event): void
{
}
public function onDiscountGroupWritten(EntityWrittenEvent $event)
{
$results = $event->getWriteResults();
foreach ($results as $result) {
$payload = $result->getPayload();
$productIds = [];
if (!empty($payload) && array_key_exists('id', $payload) && !empty($payload['id'])) {
$discountGroupId = $payload['id'];
/** @var DiscountGroupEntity $discountGroup */
$discountGroup = $this->discountGroupRepository->search((new Criteria([$discountGroupId]))->addAssociation('productStreams'), $event->getContext())->first();
if (empty($discountGroup)) continue;
switch ($discountGroup->getProductAssignmentType()) {
case DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_MATERIAL_GROUP:
if (!empty($discountGroup->getMaterialGroup())) {
$productResults = $this->productRepository->searchIds((new Criteria())->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('customFields.acris_discount_group_value', $discountGroup->getMaterialGroup()),
new EqualsFilter('customFields.acris_discount_group_product_value', $discountGroup->getMaterialGroup())
])), $event->getContext());
if ($productResults->getTotal() > 0 && $productResults->firstId()) $productIds = array_unique(array_merge($productIds, $productResults->getIds()));
}
break;
case DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_PRODUCT:
if (!empty($discountGroup->getProductId())) {
$productResults = $this->productRepository->searchIds((new Criteria([$discountGroup->getProductId()])), $event->getContext());
if ($productResults->getTotal() > 0 && $productResults->firstId()) $productIds[] = $productResults->firstId();
}
break;
default:
if (!empty($discountGroup->getProductStreams()) && $discountGroup->getProductStreams()->count() > 0) {
$productCustomIds = [];
foreach ($discountGroup->getProductStreams()->getElements() as $productStream) {
$productStreamResults = $this->productStreamMappingRepository->searchIds((new Criteria())->addFilter(new EqualsFilter('productStreamId', $productStream->getId())), $event->getContext());
if ($productStreamResults->getTotal() > 0 && $productStreamResults->getIds()) {
foreach ($productStreamResults->getIds() as $productStreamSearch) {
if (array_key_exists('productId', $productStreamSearch) && !empty($productStreamSearch['productId']) && !in_array($productStreamSearch['productId'], $productCustomIds)) {
$productCustomIds[] = $productStreamSearch['productId'];
}
}
if (!empty($productCustomIds)) {
$productResults = $this->productRepository->searchIds((new Criteria())->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsAnyFilter('id', $productCustomIds),
new EqualsAnyFilter('parentId', $productCustomIds)
])), $event->getContext());
if ($productResults->getTotal() > 0 && $productResults->firstId()) {
$productIds = array_unique(array_merge($productIds, $productResults->getIds()));
}
}
}
}
}
}
if (!empty($productIds)) {
$this->logger->invalidate(
array_map([CachedProductDetailRoute::class, 'buildName'], $productIds)
);
}
}
}
}
}