<?php declare(strict_types=1);
namespace Crehler\ImageBooster\Subscriber;
use Crehler\ImageBooster\Entity\MediaBoosterEntity;
use Crehler\ImageBooster\Enum\MediaBoosterTypeEnum;
use Crehler\ImageBooster\Message\GenerateWatermarkMessage;
use Crehler\ImageBooster\Struct\MediaBoostersStruct;
use Enqueue\MessengerAdapter\EnvelopeItem\TransportConfiguration;
use Shopware\Core\Content\Product\Aggregate\ProductMedia\ProductMediaEntity;
use Shopware\Core\Content\Product\ProductEvents;
use Shopware\Core\Content\ProductExport\Command\ProductExportGenerateCommand;
use Shopware\Core\Content\ProductExport\ScheduledTask\ProductExportPartialGeneration;
use Shopware\Core\Content\Sitemap\Commands\SitemapGenerateCommand;
use Shopware\Core\Content\Sitemap\ScheduledTask\SitemapMessage;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ProductEventsSubscriber implements EventSubscriberInterface
{
private EntityRepositoryInterface $mediaBoosterRepository;
private MessageBusInterface $messageBus;
private EntityRepositoryInterface $productMediaRepository;
private EventDispatcherInterface $eventDispatcher;
private bool $disabled = false;
public function __construct(
EntityRepositoryInterface $mediaBoosterRepository,
MessageBusInterface $messageBus,
EntityRepositoryInterface $productMediaRepository,
EventDispatcherInterface $eventDispatcher
)
{
$this->mediaBoosterRepository = $mediaBoosterRepository;
$this->messageBus = $messageBus;
$this->productMediaRepository = $productMediaRepository;
$this->eventDispatcher = $eventDispatcher;
}
public static function getSubscribedEvents(): array
{
return [
ProductEvents::PRODUCT_MEDIA_LOADED_EVENT => 'onLoadResult',
'crehler.custom_media_wrapped.loaded' => 'onLoadResult',
ProductEvents::PRODUCT_MEDIA_WRITTEN_EVENT => 'onProductMediaWritten',
ConsoleEvents::COMMAND => 'onCommand',
WorkerMessageReceivedEvent::class => 'onMessage'
];
}
public function onCommand(ConsoleCommandEvent $event)
{
if($this->disabled) return;
$this->disabled = (get_class($event->getCommand()) === SitemapGenerateCommand::class || get_class($event->getCommand()) === ProductExportGenerateCommand::class);
}
public function onMessage(WorkerMessageReceivedEvent $event)
{
if($this->disabled) return;
$this->disabled = (get_class($event->getEnvelope()->getMessage()) === SitemapMessage::class || get_class($event->getEnvelope()->getMessage()) === ProductExportPartialGeneration::class);
}
public function onLoadResult(EntityLoadedEvent $event): void
{
if ($event->getContext()->getScope() === "system" || $this->disabled) return;
$ids = [];
/** @var ProductMediaEntity $productMedia */
foreach ($event->getEntities() as $productMedia) {
if ($productMedia->getMedia()->getExtension('mediaBoosters')) {
continue;
}
$ids[] = $productMedia->getMedia()->getId();
}
$criteria = new Criteria();
$criteria->addFilter(new EqualsAnyFilter('mediaId', $ids));
$criteria->addSorting(new FieldSorting('createdAt', 'DESC'));
$result = $this->mediaBoosterRepository->search($criteria, $event->getContext())->getEntities();
$mediaBoosters = [];
/** @var MediaBoosterEntity $mediaBooster */
foreach ($result as $mediaBooster) {
$mediaBoosters[$mediaBooster->getMediaId()][] = $mediaBooster;
}
foreach ($event->getEntities() as $productMedia) {
if (isset($mediaBoosters[$productMedia->getMedia()->getId()])) {
$mediaBoosterStruct = new MediaBoostersStruct();
foreach ($mediaBoosters[$productMedia->getMedia()->getId()] as $mediaBooster) {
switch($mediaBooster->getType()) {
case MediaBoosterTypeEnum::WATERMARK_TYPE_AVIF:
$mediaBoosterStruct->setAvifMedia($mediaBooster);
break;
case MediaBoosterTypeEnum::WATERMARK_TYPE_AVIF_THUMB:
$mediaBoosterStruct->addAvifThumbnail($mediaBooster);
break;
case MediaBoosterTypeEnum::WATERMARK_TYPE_WEBP:
$mediaBoosterStruct->setWebpMedia($mediaBooster);
break;
case MediaBoosterTypeEnum::WATERMARK_TYPE_WEBP_THUMB:
$mediaBoosterStruct->addWebpThumbail($mediaBooster);
break;
case MediaBoosterTypeEnum::WATERMARK_TYPE_BASE:
$mediaBoosterStruct->setWatermark($mediaBooster);
break;
case MediaBoosterTypeEnum::WATERMARK_TYPE_BASE_THUMB:
$mediaBoosterStruct->addWatermarkThumbail($mediaBooster);
break;
}
}
$productMedia->getMedia()->addExtension('mediaBoosters', $mediaBoosterStruct);
}
}
$this->eventDispatcher->dispatch($event, 'crehler.custom_media.attach_urls');
}
public function onProductMediaWritten(EntityWrittenEvent $event): void
{
if ($event->getContext()->getScope() === "system") return;
$ids = [];
$productMedias = [];
/** @var EntityWriteResult $writeResult */
foreach ($event->getWriteResults() as $writeResult)
{
if (isset($writeResult->getPayload()['customFields']) && isset($writeResult->getPayload()['customFields']['mediaBoosterProcess'])) {
continue;
}
$productMedias[] = ['id' => $writeResult->getPrimaryKey(), 'customFields' => ['mediaBoosterProcess' => 1]];
if (isset($writeResult->getPayload()['mediaId'])) {
$ids[] = $writeResult->getPayload()['mediaId'];
}
}
if (empty($ids)) {
return;
}
$this->productMediaRepository->update($productMedias, $event->getContext());
$message = new GenerateWatermarkMessage();
$message->setMediaIds($ids);
$message->setSource("product_media");
$this->messageBus->dispatch($message, [new TransportConfiguration(['topic' => 'crehlerimagebooster'])]);
}
}