<?php
namespace CoeProductNumberSearchSw6\Subscriber;
use Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingResult;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\PrefixFilter;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepository;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Search\SearchPageLoadedEvent;
use Shopware\Storefront\Page\Suggest\SuggestPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class SuggestPageSubscriber
* @package CoeProductNumberSearchSw6\Subscriber
* @author Jeffry Block <jeffry.block@codeenterprise.de>
*/
class SuggestPageSubscriber implements EventSubscriberInterface {
private SalesChannelRepository $salesChannelProductRepository;
private SystemConfigService $systemConfigService;
public function __construct(
SalesChannelRepository $salesChannelProductRepository,
SystemConfigService $systemConfigService
) {
$this->salesChannelProductRepository = $salesChannelProductRepository;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array {
return [
SuggestPageLoadedEvent::class => "onSuggestPageLoaded",
SearchPageLoadedEvent::class => "onSearchPageLoaded"
];
}
/**
* @param SuggestPageLoadedEvent $event
* @author Jeffry Block <jeffry.block@codeenterprise.de>
*/
public function onSuggestPageLoaded(SuggestPageLoadedEvent $event) :void{
/** @var string $term */
$term = $event->getPage()->getSearchTerm();
/** @var EntitySearchResult $result */
$result = $event->getPage()->getSearchResult();
$event->getPage()->assign(['displayProductNumber' =>
$this->systemConfigService->get('CoeProductNumberSearchSw6.config.displayProductNumber',
$event->getSalesChannelContext()->getSalesChannelId())]);
#Check if the product number of the first result matches the search term
if($result->count() == 0){
return;
}
/** @var SalesChannelProductEntity $firstProduct */
$firstProduct = $result->first();
if($firstProduct === null){
return;
}
$newListingItems = $this->matchSearchString($term, $result->getEntities(), $event);
if($newListingItems){
$searchResultsItems = new EntityCollection($newListingItems);
$res = new EntitySearchResult(
$result->getEntity(),
count($newListingItems), // overwrite the count
$searchResultsItems,
$result->getAggregations(),
$result->getCriteria(),
$result->getContext()
);
$event->getPage()->setSearchResult($res);
}
}
/**
* @param SearchPageLoadedEvent $event
* @author Robin Gratz <robin.gratz@codeenterprise.de>
*/
public function onSearchPageLoaded(SearchPageLoadedEvent $event) :void{
$page = $event->getPage();
$searchTerm = $page->getSearchTerm();
/** @var ProductListingResult $listing */
$listing = $page->getListing();
$newListingItems = $this->matchSearchString($searchTerm, $listing, $event);
if ($newListingItems && $newListingItems->getTotal() > 0) {
$newListing = $this->createNewListing($newListingItems, $listing);
$page->setListing($newListing);
}
}
private function matchSearchString(string $searchTerm, $products, $event)
{
$criteria = new Criteria();
$criteria->addAssociations([
'cover',
'media'
]);
$criteria->addFilter(new EqualsFilter('productNumber', $searchTerm));
$criteria->addFilter(new NotFilter(NotFilter::CONNECTION_AND, [new EqualsFilter('active', 0)]));
$directHit = $this->salesChannelProductRepository->search($criteria, $event->getSalesChannelContext());
if($directHit && $directHit->getTotal() == 1) {
return $directHit;
}
$newListingItems = [];
if(is_numeric($searchTerm) && $this->systemConfigService->get('CoeProductNumberSearchSw6.config.numericalSearch', $event->getSalesChannelContext()->getSalesChannelId())) {
$criteria = new Criteria();
$criteria->addAssociations([
'cover',
'media'
]);
$criteria->addFilter(new PrefixFilter('productNumber', $searchTerm));
$criteria->addFilter(new NotFilter(NotFilter::CONNECTION_AND, [new EqualsFilter('active', 0)]));
$numericalHit = $this->salesChannelProductRepository->search($criteria, $event->getSalesChannelContext());
return $numericalHit;
}
return $newListingItems;
}
private function createNewListing(EntitySearchResult $searchResult, ProductListingResult $listing) :ProductListingResult
{
$newListing = new ProductListingResult(
$searchResult->getEntity(),
$searchResult->getTotal(),
$searchResult->getEntities(),
$searchResult->getAggregations(),
$listing->getCriteria(),
$searchResult->getContext(),
);
$newListing->setAvailableSortings($listing->getAvailableSortings());
return $newListing;
}
}