<?php declare(strict_types=1);
namespace CioProductDownloadsTab\Subscriber;
use CioProductDownloadsTab\Entity\ProductDownloadDefinition;
use Shopware\Core\Content\Media\MediaEntity;
use Shopware\Core\Content\Product\Events\ProductListingResultEvent;
use Shopware\Core\Content\Product\Events\ProductSearchResultEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
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\Struct\ArrayStruct;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class ProductListingSubscriber implements EventSubscriberInterface
{
private EntityRepository $productDownloadRepository;
public function __construct(EntityRepository $productDownloadRepository)
{
$this->productDownloadRepository = $productDownloadRepository;
}
public static function getSubscribedEvents(): array
{
return [
// CIO-AI-Driven: make downloads available in listing/search templates via product.extensions.productDownloads
ProductListingResultEvent::class => 'onProductListingResult',
ProductSearchResultEvent::class => 'onProductListingResult',
];
}
public function onProductListingResult(ProductListingResultEvent $event): void
{
$products = $event->getResult()->getEntities();
if ($products->count() <= 0) {
return;
}
$productIds = [];
foreach ($products as $product) {
$productIds[] = $product->getId();
}
$downloadsByProductId = $this->getDownloadsByProductIdAndType($productIds, $event->getSalesChannelContext(), ProductDownloadDefinition::TYPE_DOWNLOAD);
foreach ($products as $product) {
$downloads = $downloadsByProductId[$product->getId()] ?? [];
if ($downloads !== []) {
$product->addExtension('productDownloads', new ArrayStruct([
'downloads' => $downloads,
]));
}
}
$cadDownloadsByProductId = $this->getDownloadsByProductIdAndType($productIds, $event->getSalesChannelContext(), ProductDownloadDefinition::TYPE_CAD);
foreach ($products as $product) {
$downloads = $cadDownloadsByProductId[$product->getId()] ?? [];
if ($downloads !== []) {
$product->addExtension('productCadDownloads', new ArrayStruct([
'downloads' => $downloads,
]));
}
}
}
/**
* @param array<int, string> $productIds
*
* @return array<string, array<int, array{displayName: string, fileName: string, url: string|null}>>
*/
private function getDownloadsByProductIdAndType(array $productIds, SalesChannelContext $context, string $type): array
{
if ($productIds === []) {
return [];
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsAnyFilter('productId', $productIds));
$criteria->addFilter(new EqualsFilter('languageId', $context->getContext()->getLanguageId()));
// CIO-AI-Driven: discriminator
$criteria->addFilter(new EqualsFilter('type', $type));
$criteria->addAssociation('media');
$result = $this->productDownloadRepository->search($criteria, $context->getContext());
if ($result->getTotal() <= 0) {
return [];
}
$downloadsByProductId = [];
foreach ($result->getEntities() as $download) {
$productId = (string) $download->get('productId');
if ($productId === '') {
continue;
}
$displayName = (string) $download->get('displayName');
$fileName = (string) $download->get('fileName');
$media = $download->get('media');
$url = null;
if ($media instanceof MediaEntity) {
$url = $media->getUrl();
$fileName = $fileName !== '' ? $fileName : $this->buildFileNameFromMedia($media);
$displayName = $displayName !== '' ? $displayName : $fileName;
}
// Backward compatibility (old implementations could have filePath)
if ($url === null) {
$url = $download->get('filePath') ? (string) $download->get('filePath') : null;
}
$downloadsByProductId[$productId] ??= [];
$downloadsByProductId[$productId][] = [
'displayName' => $displayName,
'fileName' => $fileName,
'url' => $url,
];
}
return $downloadsByProductId;
}
private function buildFileNameFromMedia(MediaEntity $media): string
{
$baseName = (string) ($media->getFileName() ?? '');
$extension = (string) ($media->getFileExtension() ?? '');
if ($baseName === '') {
return '';
}
return $extension !== '' ? "{$baseName}.{$extension}" : $baseName;
}
}