<?php
namespace Abas\AbasConnector\Subscribers\Product;
use Abas\AbasConnector\Service\Customer\AbasCustomerItemNumberService;
use Abas\AbasConnector\Service\Utils\Config\PluginConfigReader;
use RuntimeException;
use Shopware\Core\Checkout\Customer\Event\CustomerLoginEvent;
use Shopware\Core\Checkout\Customer\Event\CustomerLogoutEvent;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Query\ScoreQuery;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class ProductSubscriber implements EventSubscriberInterface
{
/**
* @var Session
*/
private Session $session;
/**
* @var AbasCustomerItemNumberService
*/
private AbasCustomerItemNumberService $abasCustomerItemNumberService;
/**
* @var bool
*/
private bool $isCustomerItemNumbersActive;
/**
* ProductSubscriber constructor.
*
* @param AbasCustomerItemNumberService $abasCustomerItemNumberService
* @param Session $session
* @param PluginConfigReader $pluginConfigReader
* @throws \Exception
*/
public function __construct(
AbasCustomerItemNumberService $abasCustomerItemNumberService,
Session $session,
PluginConfigReader $pluginConfigReader
) {
$this->abasCustomerItemNumberService = $abasCustomerItemNumberService;
$this->session = $session;
$this->isCustomerItemNumbersActive = $pluginConfigReader->getIsCustomerItemNumberActive();
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents()
{
return [
CustomerLoginEvent::class => 'storeCustomerToSession',
CustomerLogoutEvent::class => 'removeCustomerToSession',
ProductEvents::PRODUCT_LOADED_EVENT => 'onProductsLoaded',
ProductSearchCriteriaEvent::class => 'addSearchCriteria',
ProductSuggestCriteriaEvent::class => 'addSuggestCriteria'
];
}
/**
* @param CustomerLoginEvent $event
*
* @return void
*/
public function storeCustomerToSession(CustomerLoginEvent $event)
{
$this->session->set("customer", $event->getCustomer()->getCustomerNumber());
}
/**
* @param CustomerLogoutEvent $event
*
* @return void
*/
public function removeCustomerToSession(CustomerLogoutEvent $event)
{
$this->session->remove("customer");
}
/**
* @param EntityLoadedEvent $event
*
* @return void
*/
public function onProductsLoaded(EntityLoadedEvent $event)
{
$customer = $this->session->get("customer");
if ($customer && $this->isCustomerItemNumbersActive) {
$this->abasCustomerItemNumberService->loadCustomerItemNumber($event->getEntities(), $customer);
}
}
/**
* @param ProductSearchCriteriaEvent $event
*
* @return void
* @throws RuntimeException
*/
public function addSearchCriteria(ProductSearchCriteriaEvent $event): void
{
$customer = $event->getSalesChannelContext()->getCustomer();
if ($customer !== null && $this->isCustomerItemNumbersActive) {
$request = $event->getRequest();
$customerProductList = $this->abasCustomerItemNumberService->loadCustomerItemsByOwnNumber(
$request->get("search"),
$customer->getCustomerNumber(),
10
);
if (count($customerProductList) > 0) {
$criteria = $event->getCriteria();
$this->updateFilters($criteria, $customerProductList);
$this->updateQueries($request->getQueryString(), $criteria, $customerProductList);
}
}
}
/**
* TODO: gleicher Methodenkörper wie addSearchCriteria().
*
* @param ProductSuggestCriteriaEvent $event
*
* @return void
* @throws RuntimeException
*/
public function addSuggestCriteria(ProductSuggestCriteriaEvent $event): void
{
$customer = $event->getSalesChannelContext()->getCustomer();
if ($customer !== null && $this->isCustomerItemNumbersActive) {
$request = $event->getRequest();
$customerProductList = $this->abasCustomerItemNumberService->loadCustomerItemsByOwnNumber(
$request->get("search"),
$customer->getCustomerNumber(),
10
);
if (count($customerProductList) > 0) {
$criteria = $event->getCriteria();
$this->updateFilters($criteria, $customerProductList);
$this->updateQueries($request->getQueryString(), $criteria, $customerProductList);
}
}
}
/**
* @param Criteria $criteria
* @param array $customerProductList
*
* @return void
*/
private function updateFilters(Criteria $criteria, array $customerProductList): void
{
$newFilters = null;
$filters = $criteria->getFilters();
foreach ($filters as $filter) {
if ($filter instanceof EqualsAnyFilter && $filter->getField() === "product.searchKeywords.keyword") {
$values = $filter->getValue();
foreach ($customerProductList as $customerProduct) {
$values[] = $customerProduct->getProduct();
}
$newFilters[] = new EqualsAnyFilter("product.searchKeywords.keyword", $values);
} else {
$newFilters[] = $filter;
}
}
if ($newFilters) {
$criteria->resetFilters();
foreach ($newFilters as $filter) {
$criteria->addFilter($filter);
}
}
}
/**
* @param string $origQuery
* @param Criteria $criteria
* @param array $customerProductList
*
* @return void
*/
private function updateQueries(string $origQuery, Criteria $criteria, array $customerProductList)
{
$newQueries = null;
$origQuery = explode("=", $origQuery)[1];
$queries = $criteria->getQueries();
foreach ($queries as $query) {
if ($query instanceof ScoreQuery && $query->getQuery()->getField() === "product.searchKeywords.keyword") {
$values[] = $origQuery;
$score = $query->getScore();
$scoreField = $query->getScoreField();
foreach ($customerProductList as $customerProduct) {
$newQueries[] = new ScoreQuery(
new ContainsFilter(
"product.searchKeywords.keyword",
$customerProduct->getProduct()
),
$score,
$scoreField
);
}
} else {
$newQueries[] = $query;
}
}
if ($newQueries) {
$criteria->resetQueries();
foreach ($newQueries as $query) {
$criteria->addQuery($query);
}
}
}
}