<?php declare(strict_types=1);
namespace System4ShopTheme\Subscriber;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Psr\Log\LoggerInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use System4ShopTheme\Struct\ColorVariantStruct;
use System4ShopTheme\Struct\ColorVariantCollection;
use Shopware\Core\Content\Product\ProductEntity;
class ListingSubscriber implements EventSubscriberInterface
{
private EntityRepository $productRepository;
private LoggerInterface $logger;
public function __construct(
EntityRepository $productRepository,
LoggerInterface $logger
) {
$this->productRepository = $productRepository;
$this->logger = $logger;
}
public static function getSubscribedEvents(): array
{
return [
ProductListingResultEvent::class => ['onProductListingResult', -10],
];
}
public function onProductListingResult(ProductListingResultEvent $event): void
{
$products = $event->getResult()->getEntities();
foreach ($products as $product) {
if (!$product->getParentId()) {
continue;
}
try {
$criteria = new Criteria([$product->getParentId()]);
$criteria->addAssociation('options.group')
->addAssociation('children')
->addAssociation('children.options.group')
->addAssociation('children.seoUrls');
$parentProduct = $this->productRepository->search(
$criteria,
$event->getSalesChannelContext()->getContext()
)->first();
if (!$parentProduct) {
continue;
}
$colorVariants = $this->getColorVariants($parentProduct);
$product->addExtension('colorVariants', $colorVariants);
} catch (\Exception $e) {
$this->logger->error('Exception occurred when loading variants in product listing result: ' .
$e->getMessage() . ",\nStack trace: " . $e->getTraceAsString());
}
}
}
private function getColorVariants($parentProduct): ColorVariantCollection
{
$colorVariants = new ColorVariantCollection();
$children = $parentProduct->getChildren();
$processedColors = []; // Track processed colors
if (!$children) {
return $colorVariants;
}
foreach ($children as $variant) {
$options = $variant->getOptions();
if (!$options) {
continue;
}
foreach ($options as $option) {
$group = $option->getGroup();
if (!$group) {
continue;
}
if (
($group->getDisplayType() === 'color' ||
strtolower($group->getTranslation('name')) === 'color')
&& $variant->getAvailable() && $variant->getActive() // Only add available variants
) {
// Create unique key based on color name and hex code
$colorKey = $option->getName() . '-' . $option->getColorHexCode();
// Skip if we've already processed this color
if (isset($processedColors[$colorKey])) {
continue;
}
$colorVariants->add(new ColorVariantStruct(
$variant->getId(),
$option->getTranslation('name'),
$option->getColorHexCode(),
$variant->getAvailable(),
$variant->getStock()
));
// Mark this color as processed
$processedColors[$colorKey] = true;
}
}
}
return $colorVariants;
}
}