<?php declare(strict_types=1);
namespace HBCTheme\Controller;
use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
use Shopware\Core\Content\Product\SalesChannel\Search\AbstractProductSearchRoute;
use Shopware\Core\Content\Product\SalesChannel\Suggest\AbstractProductSuggestRoute;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AndFilter;
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\Filter\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
use Shopware\Storefront\Page\GenericPageLoaderInterface;
use Shopware\Storefront\Page\Search\SearchPageLoader;
use Shopware\Storefront\Page\Suggest\SuggestPage;
use Shopware\Storefront\Page\Suggest\SuggestPageLoadedEvent;
use Shopware\Storefront\Page\Suggest\SuggestPageLoader;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @RouteScope(scopes={"storefront"})
*/
class DetailedSearchController extends StorefrontController
{
/**
* @var SearchPageLoader
*/
private $searchPageLoader;
/**
* @var SuggestPageLoader
*/
private $suggestPageLoader;
/**
* @var AbstractProductSearchRoute
*/
private $productSearchRoute;
/**
* @var EntityRepositoryInterface
*/
private $productRepository;
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var AbstractProductSuggestRoute
*/
private $productSuggestRoute;
/**
* @var GenericPageLoaderInterface
*/
private $genericLoader;
public function __construct(
SearchPageLoader $searchPageLoader,
SuggestPageLoader $suggestPageLoader,
AbstractProductSearchRoute $productSearchRoute,
EntityRepositoryInterface $productRepository,
EventDispatcherInterface $eventDispatcher,
AbstractProductSuggestRoute $productSuggestRoute,
GenericPageLoaderInterface $genericLoader
) {
$this->searchPageLoader = $searchPageLoader;
$this->suggestPageLoader = $suggestPageLoader;
$this->productSearchRoute = $productSearchRoute;
$this->productRepository = $productRepository;
$this->eventDispatcher = $eventDispatcher;
$this->productSuggestRoute = $productSuggestRoute;
$this->genericLoader = $genericLoader;
}
/**
* @Since("6.0.0.0")
* @HttpCache()
* @Route("/detailedsearch", name="frontend.search.page", methods={"GET"})
*/
public function search(SalesChannelContext $context, Request $request): Response
{
try {
$page = $this->searchPageLoader->load($request, $context);
$searchterm = $page->getSearchTerm();
$productId = $this->productRepository->search((new Criteria())->addAssociation('visibility')
->addAssociation('translations')
->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('productNumber', $searchterm),
new EqualsFilter('ean', $searchterm),
new EqualsFilter('product.translations.name', $searchterm)
]),
new NotFilter(NotFilter::CONNECTION_OR, [
new EqualsFilter('parentId', null)
]),
new EqualsFilter('visibilities.salesChannelId', $context->getSalesChannelId()),
new EqualsFilter('active', true)
]))
, $context->getContext())->first();
// file_put_contents('log/searchids.txt', PHP_EOL . PHP_EOL . $searchterm, FILE_APPEND);
if($productId)
{
try {
return $this->forwardToRoute('frontend.detail.page', [], ['productId' => $productId->getId()]);
}catch (\Exception $e)
{
if ($page->getListing()->getTotal() === 1) {
$product = $page->getListing()->first();
if ($request->get('search') === $product->getProductNumber()) {
$productId = $product->getId();
return $this->forwardToRoute('frontend.detail.page', [], ['productId' => $productId]);
}
}
} catch (MissingRequestParameterException $missingRequestParameterException) {
return $this->forwardToRoute('frontend.home.page');
}
}
if ($page->getListing()->getTotal() === 1) {
$product = $page->getListing()->first();
if ($request->get('search') === $product->getProductNumber()) {
$productId = $product->getId();
return $this->forwardToRoute('frontend.detail.page', [], ['productId' => $productId]);
}
}
} catch (MissingRequestParameterException $missingRequestParameterException) {
return $this->forwardToRoute('frontend.home.page');
}
return $this->renderStorefront('@Storefront/storefront/page/search/index.html.twig', ['page' => $page]);
}
/**
* @Since("6.0.0.0")
* @HttpCache()
* @Route("/suggest", name="frontend.search.suggest", methods={"GET"}, defaults={"XmlHttpRequest"=true})
*/
public function suggest(SalesChannelContext $context, Request $request): Response
{
$ids = [];
$page = $this->genericLoader->load($request, $context);
$page = SuggestPage::createFrom($page);
$page->setSearchTerm($request->query->get('search'));
$searchterm = $page->getSearchTerm();
if( (strlen($searchterm) > 5))
{
$criteria = (new Criteria())->addAssociation('visibility')
->addAssociation('translations')
->addFilter(new MultiFilter(MultiFilter::CONNECTION_AND, [
new MultiFilter(MultiFilter::CONNECTION_OR, [
new EqualsFilter('productNumber', $searchterm),
new EqualsFilter('ean', $searchterm),
new EqualsFilter('product.translations.name', $searchterm)
]),
new NotFilter(NotFilter::CONNECTION_AND, [
new EqualsFilter('parentId', null),
new EqualsFilter('product.translations.name', $searchterm)
]),
new EqualsFilter('visibilities.salesChannelId', $context->getSalesChannelId()),
new EqualsFilter('active', true)
]));
$products = $this->productRepository->search($criteria, $context->getContext());
$ids = $products->getIds();
}
$criteria = new Criteria();
if(($ids)) {
$criteria->setIds( $ids);
}
$criteria->setLimit(10);
$criteria->addAssociation('properties.group');
$criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
$page->setSearchResult(
$this->productSuggestRoute
->load($request, $context, $criteria)
->getListingResult()
);
// $page->setSearchTerm($request->query->get('search'));
$this->eventDispatcher->dispatch(
new SuggestPageLoadedEvent($page, $context, $request)
);
return $this->renderStorefront('@Storefront/storefront/layout/header/search-suggest.html.twig', ['page' => $page]);
}
/**
* @Since("6.2.0.0")
* @HttpCache()
*
* Route to load the listing filters
*
* @RouteScope(scopes={"storefront"})
* @Route("/widgets/search", name="widgets.search.pagelet.v2", methods={"GET", "POST"}, defaults={"XmlHttpRequest"=true})
*
* @throws MissingRequestParameterException
*/
public function ajax(Request $request, SalesChannelContext $context): Response
{
$request->request->set('no-aggregations', true);
$page = $this->searchPageLoader->load($request, $context);
$response = $this->renderStorefront('@Storefront/storefront/page/search/search-pagelet.html.twig', ['page' => $page]);
$response->headers->set('x-robots-tag', 'noindex');
return $response;
}
/**
* @Since("6.3.3.0")
* @HttpCache()
*
* Route to load the available listing filters
*
* @RouteScope(scopes={"storefront"})
* @Route("/widgets/search/filter", name="widgets.search.filter", methods={"GET", "POST"}, defaults={"XmlHttpRequest"=true})
*
* @throws MissingRequestParameterException
*/
public function filter(Request $request, SalesChannelContext $context): Response
{
$term = $request->get('search');
if (!$term) {
throw new MissingRequestParameterException('search');
}
// Allows to fetch only aggregations over the gateway.
$request->request->set('only-aggregations', true);
// Allows to convert all post-filters to filters. This leads to the fact that only aggregation values are returned, which are combinable with the previous applied filters.
$request->request->set('reduce-aggregations', true);
$criteria = new Criteria();
$criteria->setTitle('search-page');
$result = $this->productSearchRoute
->load($request, $context, $criteria)
->getListingResult();
$mapped = [];
foreach ($result->getAggregations() as $aggregation) {
$mapped[$aggregation->getName()] = $aggregation;
}
$response = new JsonResponse($mapped);
$response->headers->set('x-robots-tag', 'noindex');
return $response;
}
}