<?php
declare(strict_types=1);
namespace MadArticleCustomergroup\Subscriber;
use Shopware\Core\Content\Product\Aggregate\ProductVisibility\ProductVisibilityDefinition;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\SalesChannel\ProductAvailableFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Product\ProductPageCriteriaEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingsLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AndFilter;
use Bodymed\Webshop\StoreFront\Service\MadArticleCustomerGroupCheckData;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductCrossSellingIdsCriteriaEvent;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Bodymed\Webshop\Core\Content\Product\SalesChannel\Price\MadArticleVariantsListingPrice;
class ProductSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private EntityRepositoryInterface $customerGroupRepository;
private EntityRepositoryInterface $tagRepository;
private MadArticleCustomerGroupCheckData $checkData;
private MadArticleVariantsListingPrice $MadArticleVariantsListingPrice;
private SystemConfigService $systemConfigService;
public function __construct(
EntityRepositoryInterface $customerGroupRepository,
EntityRepositoryInterface $tagRepository,
MadArticleCustomerGroupCheckData $checkData,
MadArticleVariantsListingPrice $MadArticleVariantsListingPrice,
SystemConfigService $systemConfigService
)
{
$this->customerGroupRepository = $customerGroupRepository;
$this->tagRepository = $tagRepository;
$this->checkData = $checkData;
$this->MadArticleVariantsListingPrice = $MadArticleVariantsListingPrice;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
ProductPageLoadedEvent::class => 'onProductPageLoaded',
ProductListingResultEvent::class => 'onProductListingResult',
ProductSearchResultEvent::class => 'onProductListingResult',
ProductCrossSellingsLoadedEvent::class => 'onProductCrossSellingResult',
ProductSuggestCriteriaEvent::class => 'onProductSuggestCriteriaEvent',
ProductSearchCriteriaEvent::class => 'onProductSearchCriteriaEvent',
ProductListingCriteriaEvent::class => 'onProductListingCriteriaEvent',
ProductCrossSellingIdsCriteriaEvent::class => 'onProductCrossSellingIdsCriteriaEvent',
//ProductSuggestResultEvent::class => 'onProductListingResult',
//'sales_channel.product.loaded' => 'salesChannelProductLoaded',
];
}
/* Product crossselling get individuell customer prices for Variants */
public function onProductCrossSellingResult(ProductCrossSellingsLoadedEvent $event): void
{
$salesChannelContext = $event->getSalesChannelContext();
if($event->getCrossSellings()){
$crossSellings = $event->getCrossSellings()->getElements();
foreach($crossSellings as $crossSelling){
$products = $crossSelling->getProducts()->getElements();
foreach($products as $product){
$variants = $this->MadArticleVariantsListingPrice->getVariants($product, $salesChannelContext);
if($variants){
$data = new ArrayEntity(['newListPrice' => $variants]);
$product->addExtension('newListPrice', $data);
}
}
}
}
}
/* Product listing get individuell customer prices for Variants */
public function onProductListingResult(ProductListingResultEvent $event): void
{
$salesChannelContext = $event->getSalesChannelContext();
$products = $event->getResult()->getElements();
foreach($products as $product){
$variants = $this->MadArticleVariantsListingPrice->getVariants($product, $salesChannelContext);
if($variants){
$data = new ArrayEntity(['newListPrice' => $variants]);
$product->addExtension('newListPrice', $data);
}
}
}
/* Crosselling Stream */
public function onProductCrossSellingIdsCriteriaEvent(ProductCrossSellingIdsCriteriaEvent $event): void
{
$criteria = $event->getCriteria();
$customer = $event->getSalesChannelContext()->getCustomer();
$visibility = ProductVisibilityDefinition::VISIBILITY_ALL;
$criteria = $this->getCriteria($event->getSalesChannelContext()->getSalesChannel()->getId(), $criteria, $customer, $visibility);
}
/* Ajax Suche */
public function onProductSuggestCriteriaEvent(ProductSuggestCriteriaEvent $event): void
{
$criteria = $event->getCriteria();
$customer = $event->getSalesChannelContext()->getCustomer();
$visibility = ProductVisibilityDefinition::VISIBILITY_SEARCH;
$criteria = $this->getCriteria($event->getSalesChannelContext()->getSalesChannel()->getId(), $criteria, $customer, $visibility);
}
/* Suchergebnisse */
public function onProductSearchCriteriaEvent(ProductSearchCriteriaEvent $event): void
{
$criteria = $event->getCriteria();
$customer = $event->getSalesChannelContext()->getCustomer();
$visibility = ProductVisibilityDefinition::VISIBILITY_SEARCH;
$criteria = $this->getCriteria($event->getSalesChannelContext()->getSalesChannel()->getId(), $criteria, $customer, $visibility);
}
/* Listing */
public function onProductListingCriteriaEvent(ProductListingCriteriaEvent $event): void
{
$criteria = $event->getCriteria();
$customer = $event->getSalesChannelContext()->getCustomer();
$visibility = ProductVisibilityDefinition::VISIBILITY_ALL;
$criteria = $this->getCriteria($event->getSalesChannelContext()->getSalesChannel()->getId(), $criteria, $customer, $visibility);
}
public function getCriteria($id, $criteria, $customer, $visibility){
$guestGroup = $this->systemConfigService->getString('MadArticleCustomergroup.config.guestGroup');
/* Filter Customer Product Feature Visibility */
$filters = [];
if($customer !== null) {
if($customer->getGroupId() === null){
$group = $guestGroup;
}else{
$group = $customer->getGroupId();
}
if($customer->getId()){
if ($customer->getTagIds() !== null) {
foreach ($customer->getTagIds() as $tagId) {
$filters[] = new ContainsFilter('product.customFields.mad_tags_enable', $tagId);
}
}
}
$criteria->addFilter(
new MultiFilter(MultiFilter::CONNECTION_OR, [
/* Wenn Customer Produkt Feature ist wahr wird der Artikel angezeigt, da es höher Wertiger ist als die anderen Prüfungen */
new MultiFilter(MultiFilter::CONNECTION_AND, [
new EqualsFilter('customerProductFeature.customerId', $customer->getId()),
new EqualsFilter('customerProductFeature.visible', true)
]),
new MultiFilter(MultiFilter::CONNECTION_AND, [
new NotFilter(NotFilter::CONNECTION_AND, [
new EqualsFilter('customerProductFeature.customerId', $customer->getId()),
new EqualsFilter('customerProductFeature.visible', false),
]),
new MultiFilter(MultiFilter::CONNECTION_OR, [
/* Prüfen ob der Tag gesetzt ist und das Produkt Feature nicht */
new MultiFilter(MultiFilter::CONNECTION_OR, $filters),
/* Prüfen ob die Gruppe vorhanden ist */
new MultiFilter(MultiFilter::CONNECTION_AND, [
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('product.customFields.mad_tags_enable', Null),
new EqualsFilter('product.customFields.mad_tags_enable', '[]'),
]),
new MultiFilter(MultiFilter::CONNECTION_OR, [
new ContainsFilter('product.customFields.mad_usergroups_enable', $group),
])
]),
])
]),
new MultiFilter(MultiFilter::CONNECTION_AND, [
new NotFilter(NotFilter::CONNECTION_AND, [
new EqualsFilter('customerProductFeature.customerId', $customer->getId()),
new EqualsFilter('customerProductFeature.visible', false),
]),
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('product.customFields.mad_tags_enable', Null),
new EqualsFilter('product.customFields.mad_tags_enable', '[]'),
]),
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('product.customFields.mad_usergroups_enable', Null),
new EqualsFilter('product.customFields.mad_usergroups_enable', '[]'),
]),
new ProductAvailableFilter($id, $visibility)
]),
])
);
}else{ /* Kein Kunde */
$criteria->addFilter(
new MultiFilter(MultiFilter::CONNECTION_OR, [
new ContainsFilter('product.customFields.mad_usergroups_enable', $guestGroup),
new MultiFilter(MultiFilter::CONNECTION_AND, [
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('product.customFields.mad_tags_enable', Null),
new EqualsFilter('product.customFields.mad_tags_enable', '[]'),
]),
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('product.customFields.mad_usergroups_enable', Null),
new EqualsFilter('product.customFields.mad_usergroups_enable', '[]'),
]),
new ProductAvailableFilter($id, $visibility)
]),
])
);
}
return $criteria;
}
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$salesChannelContext = $event->getSalesChannelContext();
$product = $event->getPage()->getProduct();
$product->MadShowArticle = true;
$product->MadShowTagArticle = true;
$guestGroup = $this->systemConfigService->getString('MadArticleCustomergroup.config.guestGroup');
if(!$this->checkData->checkArticleVisibility($salesChannelContext->getCustomer(), $product , $guestGroup)){
if($salesChannelContext->getCustomer() == null){
$product->MadLogin = false;
}else{
$product->MadLogin = true;
}
$product->MadShowArticle = false;
}
}
}