<?php declare(strict_types=1);
namespace App\RabbitMq\Handler;
use App\Contract\Content\DownloadableContent;
use App\Contract\Content\DownloadableContentBid;
use App\Entity\Deal;
use App\Entity\DealBid;
use App\Entity\Download;
use App\Entity\Message\MessageBid;
use App\Entity\Message\MessageReception;
use App\Entity\Project;
use App\Entity\ProjectBid;
use App\Entity\ShopVideo;
use App\Entity\ShopVideoBid;
use App\RabbitMq\Processing\PopProcessingEvent;
use App\RabbitMq\Processing\ProcessingEvent;
use App\RabbitMq\Processing\PushProcessingEvent;
use App\Repository\DownloadRepository;
use App\Repository\Filter\DownloadableContentFilter;
use Doctrine\Common\Collections\Collection;
use Doctrine\Persistence\ManagerRegistry;
use InvalidArgumentException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
class DownloadableContentHandler implements RabbitMqHandlerInterface, EventSubscriberInterface
{
public const ADD = 'add';
public const REMOVE = 'remove';
private ManagerRegistry $doctrine;
private DownloadRepository $downloadRepository;
public function __construct(ManagerRegistry $doctrine, DownloadRepository $downloadRepository)
{
$this->doctrine = $doctrine;
$this->downloadRepository = $downloadRepository;
}
public function supports(string $service): bool
{
return $service === self::class;
}
/**
* @param mixed[] $task
*/
public function handle(?object $entity, array $task): void
{
if (!is_array($task['arguments']) || 1 !== count($task['arguments'])) {
throw new InvalidArgumentException('Task should contain only one argument.');
}
if (!$entity instanceof DownloadableContent) {
throw new UnexpectedTypeException($entity, DownloadableContent::class);
}
if (!$entity instanceof Deal && !$entity instanceof Project && !$entity instanceof ShopVideo && !$entity instanceof MessageReception) {
throw new UnexpectedTypeException($entity, implode('|', [Deal::class, Project::class, ShopVideo::class, MessageReception::class]));
}
if (!is_string($task['arguments'][0])) {
return;
}
$action = $task['arguments'][0];
if (self::ADD !== $action && self::REMOVE !== $action) {
throw new UnexpectedValueException($action, '"add"|"remove"');
}
if ($action === self::REMOVE) {
if ($entity->isContentAccessible()) {
return;
}
$downloads = $this->downloadRepository->filterResults([
DownloadableContentFilter::FILTER => $entity,
]);
foreach ($downloads as $download) {
$this->doctrine->getManager()->remove($download);
}
return;
}
if (!$entity->isContentAccessible()) {
return;
}
/** @var Collection<int, DownloadableContentBid<DealBid|ProjectBid|ShopVideoBid|MessageBid>> $bids */
$bids = $entity->getBids();
foreach ($bids as $bid) {
if (!$bid->isStillAccessible()) {
continue;
}
$download = new Download($bid->getUser(), $entity);
$this->doctrine->getManager()->persist($download);
}
}
public function onPushProcess(PushProcessingEvent $event): void
{
$this->onProcess($event);
}
public function onPopProcess(PopProcessingEvent $event): void
{
$this->onProcess($event);
}
private function onProcess(ProcessingEvent $event): void
{
if ($event->getService() !== self::class) {
return;
}
$entity = $event->getEntity();
if (!$entity instanceof DownloadableContent) {
return;
}
$event->stopPropagation();
}
/**
* @return array<string, array<int|string, array<int|string, int|string>|int|string>|string>
*/
public static function getSubscribedEvents(): array
{
return [
PushProcessingEvent::class => ['onPushProcess', 1000],
PopProcessingEvent::class => ['onPopProcess', 1000],
];
}
}