<?php declare(strict_types=1);
namespace Asbs\ImageAnalyzer\Subscriber;
use Asbs\ImageAnalyzer\Message\AnalyzeMediaMessage;
use Asbs\ImageAnalyzer\Service\MediaAnalyzer;
use Shopware\Core\Content\Media\MediaEvents;
use Shopware\Core\Content\Media\Event\MediaUploadedEvent;
use Shopware\Core\Content\Media\Message\GenerateThumbnailsMessage;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Psr\Log\LoggerInterface;
class MediaUploadSubscriber implements EventSubscriberInterface
{
private MediaAnalyzer $mediaAnalyzer;
private SystemConfigService $systemConfigService;
private LoggerInterface $logger;
private EntityRepositoryInterface $mediaRepository;
private MessageBusInterface $messageBus;
public function __construct(
MediaAnalyzer $mediaAnalyzer,
SystemConfigService $systemConfigService,
LoggerInterface $logger,
EntityRepositoryInterface $mediaRepository,
MessageBusInterface $messageBus
) {
$this->mediaAnalyzer = $mediaAnalyzer;
$this->systemConfigService = $systemConfigService;
$this->logger = $logger;
$this->mediaRepository = $mediaRepository;
$this->messageBus = $messageBus;
}
public static function getSubscribedEvents(): array
{
return [
MediaEvents::MEDIA_WRITTEN_EVENT => 'onMediaWritten',
MediaUploadedEvent::class => 'onMediaUploaded',
MediaEvents::MEDIA_LOADED_EVENT => 'onMediaLoaded',
];
}
public function onMediaWritten(EntityWrittenEvent $event): void
{
$this->logger->info('MediaUploadSubscriber::onMediaWritten triggered');
$autoAnalyze = $this->systemConfigService->get('AsbsImageAnalyzer.config.autoAnalyze');
$this->logger->info('Auto-analyze config value: ' . var_export($autoAnalyze, true));
if (!$autoAnalyze) {
$this->logger->info('Auto-analyze is disabled');
return;
}
$context = $event->getContext();
foreach ($event->getWriteResults() as $writeResult) {
$this->logger->info('Processing write result', [
'operation' => $writeResult->getOperation(),
'entity' => $writeResult->getEntityName()
]);
// Handle both insert and update operations
if (!in_array($writeResult->getOperation(), ['insert', 'update'], true)) {
$this->logger->info('Skipping operation: ' . $writeResult->getOperation());
continue;
}
$payload = $writeResult->getPayload();
$this->logger->info('Payload data', [
'id' => $payload['id'] ?? 'not set',
'mimeType' => $payload['mimeType'] ?? 'not set',
'alt' => $payload['alt'] ?? 'not set',
'hasFile' => isset($payload['uploadedAt']) ? 'yes' : 'no'
]);
if (!isset($payload['id']) || !isset($payload['mimeType'])) {
$this->logger->info('Missing id or mimeType, skipping');
continue;
}
// Skip if alt text already exists (optional check)
if (isset($payload['alt']) && !empty($payload['alt'])) {
$this->logger->info('Media already has alt text, skipping: ' . $payload['id']);
continue;
}
// Check if this is an image
if (strpos($payload['mimeType'], 'image/') !== 0) {
$this->logger->info('Media is not an image, skipping: ' . $payload['id']);
continue;
}
// For update operations, check if this is the upload completing
if ($writeResult->getOperation() === 'update') {
// Only process if we're updating with file data
if (!isset($payload['uploadedAt']) && !isset($payload['fileName']) && !isset($payload['fileSize'])) {
$this->logger->info('Update operation but no file data, skipping');
continue;
}
} else {
// For insert operations, skip if file not yet uploaded
if (!isset($payload['uploadedAt']) && !isset($payload['fileName'])) {
$this->logger->info('Insert operation but file not yet uploaded, skipping: ' . $payload['id']);
continue;
}
}
$this->logger->info('Found new media for auto-analysis: ' . $payload['id']);
try {
// Send analysis to message queue for async processing
$message = new AnalyzeMediaMessage($payload['id']);
$this->messageBus->dispatch($message);
$this->logger->info('Dispatched media analysis message for: ' . $payload['id']);
} catch (\Exception $e) {
$this->logger->error('Failed to dispatch media analysis message: ' . $e->getMessage(), [
'mediaId' => $payload['id'],
'exception' => $e->getMessage()
]);
}
}
}
public function onMediaUploaded(MediaUploadedEvent $event): void
{
$autoAnalyze = $this->systemConfigService->get('AsbsImageAnalyzer.config.autoAnalyze');
$this->logger->info('MediaUploadedEvent triggered, auto-analyze config: ' . var_export($autoAnalyze, true));
if (!$autoAnalyze) {
$this->logger->info('Auto-analyze is disabled in configuration');
return;
}
$mediaId = $event->getMediaId();
$context = $event->getContext();
$this->logger->info('Processing uploaded media ID: ' . $mediaId);
try {
$criteria = new Criteria([$mediaId]);
$criteria->addAssociation('mediaFolder');
$media = $this->mediaRepository->search($criteria, $context)->first();
if ($media) {
// Check if it's an image
$mimeType = $media->getMimeType();
if (!$mimeType || strpos($mimeType, 'image/') !== 0) {
$this->logger->info('Uploaded media is not an image, skipping. MimeType: ' . ($mimeType ?? 'null'));
return;
}
// Check if alt text already exists
if ($media->getAlt()) {
$this->logger->info('Media already has alt text, skipping: ' . $media->getAlt());
return;
}
$this->logger->info('Starting analysis for uploaded media: ' . $mediaId);
$result = $this->mediaAnalyzer->analyzeMedia($media, $context);
$this->logger->info('Analysis completed for media: ' . $mediaId . ', result: ' . json_encode($result));
} else {
$this->logger->warning('Media entity not found after upload: ' . $mediaId);
}
} catch (\Exception $e) {
$this->logger->error('Failed to auto-analyze uploaded media: ' . $e->getMessage(), [
'mediaId' => $mediaId,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
}
public function onMediaLoaded(EntityLoadedEvent $event): void
{
// This is just for debugging to see if events are triggered
$this->logger->info('MediaUploadSubscriber::onMediaLoaded triggered');
}
}