<?php
declare(strict_types=1);
namespace XantenLastSeenProduct\Controller;
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\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Grouping\FieldGrouping;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Controller\StorefrontController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* @RouteScope(scopes={"storefront"})
*/
class LastSeenProductController extends StorefrontController
{
public const LAST_SEEN_PRODUCTS = 'seen-products';
/**
* @var SalesChannelRepositoryInterface
*/
private $productRepository;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* LastSeenProductController constructor.
*/
public function __construct(SalesChannelRepositoryInterface $productRepository, SystemConfigService $systemConfigService)
{
$this->productRepository = $productRepository;
$this->systemConfigService = $systemConfigService;
}
/**
* @Route("/lastseen-product/add", name="frontend.last.seen.product.add", methods={"POST"}, defaults={"csrf_protected"=false, "XmlHttpRequest"=true})
*/
public function addLastSeenProduct(Request $request, SalesChannelContext $context)
{
$productId = $request->request->get('productId');
if (!$productId) {
return new JsonResponse([], 400);
}
$seenProductIds = $request->getSession()->get(self::LAST_SEEN_PRODUCTS, null);
if (!$seenProductIds) {
$seenProductIds = $productId;
} else {
$maxProducts = $this->systemConfigService->get('XantenLastSeenProduct.config.maxProducts');
$seenProductIds = explode('|', $seenProductIds);
$added = array_search($productId, $seenProductIds);
if (false !== $added) {
unset($seenProductIds[$added]);
}
array_unshift($seenProductIds, $productId);
$seenProductIds = array_slice($seenProductIds, 0, $maxProducts);
$seenProductIds = implode('|', $seenProductIds);
}
$request->getSession()->set(self::LAST_SEEN_PRODUCTS, $seenProductIds);
return new JsonResponse();
}
/**
* @Route("/widgets/lastseen-product", name="frontend.last.seen.product.page", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
*/
public function index(Request $request, SalesChannelContext $context)
{
$seenProductIds = $request->getSession()->get(self::LAST_SEEN_PRODUCTS);
$minimumItems = (int) $request->get('minItems', 4);
$maximumItems = (int) $request->get('maxItems', 16);
$layout = $request->get('layout', 'standard');
$displayMode = $request->get('displayMode', 'standard');
$skipProductId = $request->get('skipProductId');
$result = $this->getProducts($seenProductIds, $skipProductId, $minimumItems, $maximumItems, $context);
$products = $result->getElements();
if ($result->count()) {
$seenProductIds = explode('|', $seenProductIds);
$products = array_merge(array_flip($seenProductIds), $products);
$products = array_filter($products, function ($product) {
return $product instanceof SalesChannelProductEntity;
});
}
return $this->renderStorefront(
'@XantenLastSeenProduct/storefront/component/product-slider.html.twig',
[
'products' => $products,
'layout' => $layout,
'displayMode' => $displayMode
]
);
}
/**
* @param string|null $seenProductIds
* @param string|null $skipProductId
* @param int $minimumItems
* @param int $maximumItems
* @param SalesChannelContext $context
*
* @return \Shopware\Core\Framework\DataAbstractionLayer\EntityCollection
*/
private function getProducts($seenProductIds, $skipProductId, $minimumItems, $maximumItems, $context)
{
if (!$seenProductIds) {
return new EntityCollection();
}
$seenProductIds = explode('|', $seenProductIds);
if (count($seenProductIds) < $minimumItems) {
return new EntityCollection();
}
$criteria = new Criteria($seenProductIds);
$criteria->addAssociation('cover');
$criteria->setLimit($maximumItems);
if ($skipProductId) {
$criteria->addFilter(new NotFilter(NotFilter::CONNECTION_AND, [
new EqualsFilter('id', $skipProductId)
]));
}
$criteria->addFilter(
new NotFilter(
NotFilter::CONNECTION_AND,
[new EqualsFilter('displayGroup', null)]
)
);
$criteria->addGroupField(new FieldGrouping('displayGroup'));
return $this->productRepository->search($criteria, $context)->getEntities();
}
}