<?php declare(strict_types=1);
namespace GlobusSW6\Subscriber\ArticleVisibility;
use GlobusSW6\Core\IaneoDefaults;
use GlobusSW6\Service\ArticleVisibilityService;
use GlobusSW6\Service\ChangeVisibilityService;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\Api\Context\SalesChannelApiSource;
use Shopware\Core\Framework\Api\Context\SystemSource;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
use Shopware\Core\Content\Product\ProductCollection;
use Shopware\Core\Framework\Api\Context\AdminApiSource;
use Psr\Log\LoggerInterface;
class ArticleVisibilitySubscriber implements EventSubscriberInterface
{
/** @var ArticleVisibilityService */
private $articleVisibilityService;
/** @var ChangeVisibilityService */
private $changeVisibilityService;
/** @var LoggerInterface */
private $logger;
/**
* ArticleVisibilitySubscriber constructor.
* @param ArticleVisibilityService $articleVisibilityService
* @param ChangeVisibilityService $changeVisibilityService
* @param LoggerInterface $logger
*/
public function __construct(
ArticleVisibilityService $articleVisibilityService,
ChangeVisibilityService $changeVisibilityService,
LoggerInterface $logger
) {
$this->articleVisibilityService = $articleVisibilityService;
$this->changeVisibilityService = $changeVisibilityService;
$this->logger = $logger;
}
public static function getSubscribedEvents(): array
{
return [
'product.search.result.loaded' => 'onProductLoaded',
'product.written' => 'onProductWritten',
];
}
/**
* Nicht auf Admin beschränken, damit später auch Zuweisungen via API möglich sind.
* Automatisiertes Zuweisen von SalesChannels anhand der zugewiesenen Kategorie
*
* @param EntityWrittenEvent $entityWrittenEvent
*/
public function onProductWritten(EntityWrittenEvent $entityWrittenEvent): void
{
//TODO: Fälle unterscheiden Storefront oder Admin Event
// SalesChannelId in AdminSource nicht verfügbar --> catch-Fall tritt direkt ein
$context = $entityWrittenEvent->getContext();
try {
$salesChannelId = $entityWrittenEvent->getContext()->getSource()->getSalesChannelId();
} catch (\Throwable $t) {
$this->logger->info('Unable to access salesChannelId');
return;
}
/** @var EntityWriteResult $writeResults */
foreach ($entityWrittenEvent->getWriteResults() as $writeResult) {
$productId = $writeResult->getPrimaryKey();
if (!$context->hasExtension('ianeoArticleApi')) {
// Visibility - Kategorie- SalesChanel-Zuweisung
$this->articleVisibilityService->handleArticleVisibilityBySelectedCategory($productId);
// visibility ändern falls notwendig
$productEntities = $this->articleVisibilityService->getProductCollectionByProductIds(
$productId,
$entityWrittenEvent->getContext()
);
$visibilities = $this->articleVisibilityService->handleArticleVisibility($productEntities, $salesChannelId);
$invisibleProductIds = array_keys($visibilities);
$productHasNoStock = false;
$productIdWithNoStock = '';
foreach($invisibleProductIds as $invisibleProductId){
if( isset($visibilities[$invisibleProductId])){
foreach($visibilities[$invisibleProductId] as $visibility){
//TODO-INI: currently hardcoded
if($visibility === 'Das Produkt hat keinen Bestand.'){
$productHasNoStock = true;
$productIdWithNoStock = $invisibleProductId;
}
}
}
}
if (!in_array($productId, $invisibleProductIds)) {
$this->changeVisibilityService->setVisibilityTo30(
$productId,
$salesChannelId
);
} else {
if($productHasNoStock && $productId === $productIdWithNoStock){
$this->changeVisibilityService->setVisibilityTo10(
$productId,
$salesChannelId
);
}else{
$this->changeVisibilityService->setVisibilityToZero(
[$productId],
$salesChannelId
);
}
}
}
}
}
public function onProductLoaded(EntitySearchResultLoadedEvent $event)
{
// do not fire event in backend context
if ($event->getContext()->getSource() instanceof AdminApiSource) {
if ($event->getContext()->getSource()->isAdmin()) {
return;
}
}
if ($event->getContext()->getSource() instanceof SystemSource) {
return;
}
$salesChannelId = $event->getContext()->getSource()->getSalesChannelId();
/** @var ProductCollection $products */
$products = $event->getResult()->getEntities();
if ($products === null || !($event->getContext()->getSource() instanceof SalesChannelApiSource)) {
return;
}
foreach ($products as $product) {
try {
// $this->logger->info('Product attributes of ' . $product->getName() . ' ' . $product->getProductNumber() . ' : ' . json_encode($product->getExtensions()['ianeoAttributes']));
// $this->logger->info('Product extension of ' . $product->getName() . ' ' . $product->getProductNumber() . ' : ' . json_encode($product->getExtensions()['ianeoExtensions']));
} catch (\Throwable $t) {
}
}
// collect visibilities for each product
$visibilities = $this->articleVisibilityService->handleArticleVisibility($products, $salesChannelId);
$invisibleProductIds = array_keys($visibilities);
$salesChannelId = $event->getContext()->getSource()->getSalesChannelId();
// ProductHasNoStock
$productHasNoStock = false;
$productIdWithNoStock = '';
foreach($invisibleProductIds as $invisibleProductId){
if( isset($visibilities[$invisibleProductId])){
foreach($visibilities[$invisibleProductId] as $visibility){
//TODO-INI: currently hardcoded
if($visibility === 'Das Produkt hat keinen Bestand.'){
$productHasNoStock = true;
$productIdWithNoStock = $invisibleProductId;
}
}
}
}
if($productHasNoStock){
$this->changeVisibilityService->setVisibilityTo10(
$invisibleProductId,
$salesChannelId
);
}else{
// visibility is set to 0 for future search
$this->changeVisibilityService->setVisibilityToZero(
$invisibleProductIds,
$salesChannelId);
}
// also remove these products from current search result
foreach ($invisibleProductIds as $productId) {
$products->remove($productId);
}
}
}