<?php declare(strict_types=1);
namespace App\RabbitMq\Handler;
use App\Contract\Content\DownloadableContentBid;
use App\Entity\Deal;
use App\Entity\Download;
use App\Entity\Message\MessageReception;
use App\Entity\Project;
use App\Entity\ShopVideo;
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 App\Repository\Filter\UserBids;
use Doctrine\Persistence\ManagerRegistry;
use InvalidArgumentException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
class DownloadableContentBidHandler 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 DownloadableContentBid) {
throw new UnexpectedTypeException($entity, DownloadableContentBid::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 (self::ADD === $action && (!$entity->isStillAccessible() || !$entity->getContent()->isContentAccessible())) {
return;
}
if (self::REMOVE === $action && $entity->isStillAccessible()) {
return;
}
$downloadableContent = $entity->getContent();
if (!$downloadableContent instanceof Deal && !$downloadableContent instanceof Project && !$downloadableContent instanceof ShopVideo && !$downloadableContent instanceof MessageReception) {
throw new UnexpectedTypeException($downloadableContent, implode('|', [Deal::class, Project::class, ShopVideo::class, MessageReception::class]));
}
$downloads = $this->downloadRepository->filterResults([
DownloadableContentFilter::FILTER => $downloadableContent,
UserBids::FILTER => $entity->getUser(),
]);
if (self::ADD === $action) {
if (1 === count($downloads)) {
// already has it
return;
}
if (0 === count($downloads)) {
$download = new Download($entity->getUser(), $downloadableContent);
$this->doctrine->getManager()->persist($download);
return;
}
// slip to remove, but leave one entry
array_shift($downloads);
}
foreach ($downloads as $download) {
$this->doctrine->getManager()->remove($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 DownloadableContentBid) {
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],
];
}
}