<?php
namespace Ks\KsAdditions\Subscribers\Product\Listing;
use Doctrine\DBAL\Connection;
use Ks\KsAdditions\KsAdditions;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MinAggregation;
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\MultiFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ListingSubscriber implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private EntityRepositoryInterface $productRepository;
/**
* @var SalesChannelRepositoryInterface
*/
private SalesChannelRepositoryInterface $salesChannelProductRepository;
/** @var Connection */
private $connection;
/**
* @param EntityRepositoryInterface $productRepository
* @param SalesChannelRepositoryInterface $salesChannelProductRepository
* @param Connection $connection
*/
public function __construct(
EntityRepositoryInterface $productRepository,
SalesChannelRepositoryInterface $salesChannelProductRepository,
Connection $connection
) {
$this->productRepository = $productRepository;
$this->salesChannelProductRepository = $salesChannelProductRepository;
$this->connection = $connection;
}
/**
* @return \array[][]
*/
public static function getSubscribedEvents(): array
{
return [
ProductListingResultEvent::class => ['handleListingResult', 0],
];
}
/**
* @param ProductListingResultEvent $event
* @return void
*/
public function handleListingResult(ProductListingResultEvent $event): void
{
$context = $event->getContext();
$currentCategoryId = $event->getResult()->getCurrentFilter('navigationId');
$criteria = new Criteria();
$criteria->addFilter(
new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsAnyFilter('categoryTree', [$currentCategoryId]),
new RangeFilter('stock', [
RangeFilter::GT => 0
]),
]
)
);
$criteria->addAggregation(
new MaxAggregation('max-passung', 'product.customFields.' . KsAdditions::ADDVISOR_PASSUNG_MAX),
new MinAggregation('min-passung', 'product.customFields.' . KsAdditions::ADDVISOR_PASSUNG_MIN),
);
$result = $this->productRepository->search($criteria, $context);
$event->getResult()->addExtension('passung', new ArrayStruct([
'max' => $result->getAggregations()->get('max-passung')->getMax(),
'min' => $result->getAggregations()->get('min-passung')->getMin(),
]));
$currentPassung = $event->getRequest()->get('passung');
if ($currentPassung) {
foreach ($event->getResult()->getEntities() as $product) {
$bestVariant = $this->findBestVariant($product, (int) $currentPassung, $event->getSalesChannelContext());
if ($bestVariant) {
$product->assign(['KsBestVariant' => $bestVariant]);
}
}
}
}
private function findBestVariant($product, $currentPassung, $salesChanneContext)
{
$criteria = new Criteria();
$criteria->addFilter(
new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new RangeFilter('stock', [
RangeFilter::GT => 0
]),
new RangeFilter('product.customFields.' . KsAdditions::ADDVISOR_PASSUNG_MIN, [
RangeFilter::LTE => $currentPassung
]),
new RangeFilter('product.customFields.' . KsAdditions::ADDVISOR_PASSUNG_MAX, [
RangeFilter::GTE => $currentPassung
]),
]
)
);
if (!$product->getParentId()) {
$criteria->addFilter(new EqualsFilter('product.parentId', $product->getId()));
} else {
$criteria->addFilter(new EqualsFilter('product.parentId', $product->getParentId()));
}
$criteria->addSorting(new FieldSorting('product.stock', FieldSorting::DESCENDING));
$criteria->addAssociation('prices')
->addAssociation('unit')
->addAssociation('deliveryTime')
->addAssociation('cover.media');
$result = $this->salesChannelProductRepository->search($criteria, $salesChanneContext);
return $result->getTotal() > 0 ? $result->first() : null;
}
}