<?php declare(strict_types=1);
namespace Acris\DiscountGroup\Components;
use Acris\DiscountGroup\Components\Event\DiscountGroupGatewayFilterParameterEvent;
use Acris\DiscountGroup\Components\Filter\DiscountGroupActiveDataRangeFilter;
use Acris\DiscountGroup\Custom\DiscountGroupDefinition;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
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 Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class DiscountGroupGateway
{
private EntityRepositoryInterface $discountGroupRepository;
private EntityRepositoryInterface $productStreamMappingRepository;
/**
* @var EntitySearchResult|array|null
*/
private $discountGroupSearchResult;
private EventDispatcherInterface $eventDispatcher;
public function __construct(
EntityRepositoryInterface $discountGroupRepository,
EntityRepositoryInterface $productStreamMappingRepository,
EventDispatcherInterface $eventDispatcher
) {
$this->discountGroupRepository = $discountGroupRepository;
$this->productStreamMappingRepository = $productStreamMappingRepository;
$this->eventDispatcher = $eventDispatcher;
$this->discountGroupSearchResult = [];
}
public function getAllDiscountGroups(SalesChannelContext $salesChannelContext, ?string $productId = null, ?array $productStreamIds = null): EntitySearchResult
{
if(!empty($productId) && !empty($this->discountGroupSearchResult) && is_array($this->discountGroupSearchResult) && array_key_exists($productId, $this->discountGroupSearchResult)
&& !empty($this->discountGroupSearchResult[$productId]) && $this->discountGroupSearchResult[$productId] instanceof EntitySearchResult) {
return $this->discountGroupSearchResult[$productId];
}
elseif (empty($productId) && !empty($this->discountGroupSearchResult) && $this->discountGroupSearchResult instanceof EntitySearchResult) {
return $this->discountGroupSearchResult;
}
$criteria = (new Criteria());
$criteria = $this->addCriteria($productStreamIds, $productId, $criteria, $salesChannelContext);
if (!empty($productId)) {
$this->discountGroupSearchResult[$productId] = $this->discountGroupRepository->search($criteria, $salesChannelContext->getContext());
return $this->discountGroupSearchResult[$productId];
} else {
$this->discountGroupSearchResult = $this->discountGroupRepository->search($criteria, $salesChannelContext->getContext());
return $this->discountGroupSearchResult;
}
}
private function addCriteria(?array $productStreamIds, ?string $productId, Criteria $criteria, SalesChannelContext $salesChannelContext): Criteria
{
$customer = $salesChannelContext->getCustomer();
$customerIds = !empty($customer) ? [$customer->getId()] : [];
$discountGroupValues = [];
if(!empty($customer) && !empty($customer->getCustomFields())) {
if(array_key_exists('acris_discount_group_customer_value', $customer->getCustomFields()) && !empty($customer->getCustomFields()['acris_discount_group_customer_value'])) {
$discountGroupValues = [$customer->getCustomFields()['acris_discount_group_customer_value']];
} elseif(array_key_exists('acris_discount_group_value', $customer->getCustomFields()) && !empty($customer->getCustomFields()['acris_discount_group_value'])) {
$discountGroupValues = [$customer->getCustomFields()['acris_discount_group_value']];
}
}
$event = new DiscountGroupGatewayFilterParameterEvent($customerIds, $discountGroupValues, $salesChannelContext);
$this->eventDispatcher->dispatch($event);
$customerFilters = [
new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('customerAssignmentType', DiscountGroupDefinition::CUSTOMER_ASSIGNMENT_TYPE_CUSTOMER_RULES),
new EqualsAnyFilter('rules.id', $salesChannelContext->getRuleIds()),
])
];
if(!empty($event->getDiscountGroupValues())) {
array_unshift($customerFilters, new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('customerAssignmentType', DiscountGroupDefinition::CUSTOMER_ASSIGNMENT_TYPE_CUSTOMER_DISCOUNT_GROUP),
new EqualsAnyFilter('discountGroup', $event->getDiscountGroupValues()),
]));
}
if(!empty($event->getCustomerIds())) {
array_unshift($customerFilters, new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('customerAssignmentType', DiscountGroupDefinition::CUSTOMER_ASSIGNMENT_TYPE_CUSTOMER),
new EqualsAnyFilter('customerId', $event->getCustomerIds())
]));
}
$activeFilter = new DiscountGroupActiveDataRangeFilter();
$criteria->addAssociation('rules')
->addAssociation('productStreams')
->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [
new MultiFilter(MultiFilter::CONNECTION_OR, $customerFilters),
new EqualsFilter('active', true),
$activeFilter
]))
->addSorting(new FieldSorting('priority', FieldSorting::DESCENDING));
if (is_array($productStreamIds)) {
$criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
new NotFilter(MultiFilter::CONNECTION_AND, [new EqualsFilter('productAssignmentType', DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_DYNAMIC_PRODUCT_GROUP)]),
new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('productAssignmentType', DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_DYNAMIC_PRODUCT_GROUP),
new EqualsAnyFilter('productStreams.id', $productStreamIds),
new NotFilter(NotFilter::CONNECTION_AND, [
new EqualsFilter('productStreams.id', null)
])
])
]));
}
if (!empty($productId)) {
$criteria->addFilter(new MultiFilter(MultiFilter::CONNECTION_OR, [
new NotFilter(MultiFilter::CONNECTION_AND, [new EqualsFilter('productAssignmentType', DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_PRODUCT)]),
new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('productAssignmentType', DiscountGroupDefinition::PRODUCT_ASSIGNMENT_TYPE_PRODUCT),
new EqualsFilter('productId', $productId)
])
]));
}
return $criteria;
}
public function getProductStreamIds(array $productIds, Context $context): array
{
$productStreamIds = [];
$idSearchResult = $this->productStreamMappingRepository->searchIds((new Criteria())->addFilter(new EqualsAnyFilter('productId', $productIds)), $context);
if ($idSearchResult->getTotal() > 0) {
foreach ($idSearchResult->getIds() as $ids) {
if (!empty($ids) && is_array($ids) && array_key_exists('productStreamId', $ids) && !empty($ids['productStreamId'])) {
$productStreamIds[] = $ids['productStreamId'];
}
}
}
return $productStreamIds;
}
}