Dispatcher::getWorkflow()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 10
cc 2
nc 2
nop 1
crap 2.032
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Setono\MessageSchedulerBundle\Dispatcher;
6
7
use Doctrine\Persistence\ManagerRegistry;
8
use Doctrine\Persistence\ObjectManager;
9
use LogicException;
10
use Psr\Log\LoggerAwareInterface;
11
use Psr\Log\LoggerInterface;
12
use Psr\Log\NullLogger;
13
use RuntimeException;
14
use function Safe\sprintf;
15
use Setono\MessageSchedulerBundle\Message\Command\DispatchScheduledMessage;
16
use Setono\MessageSchedulerBundle\Repository\ScheduledMessageRepositoryInterface;
17
use Setono\MessageSchedulerBundle\Workflow\ScheduledMessageWorkflow;
18
use Symfony\Component\Messenger\MessageBusInterface;
19
use Symfony\Component\Workflow\Registry;
20
use Symfony\Component\Workflow\Workflow;
21
22
final class Dispatcher implements DispatcherInterface, LoggerAwareInterface
23
{
24
    private ?ObjectManager $objectManager = null;
25
26
    private LoggerInterface $logger;
27
28
    private MessageBusInterface $commandBus;
29
30
    private ScheduledMessageRepositoryInterface $scheduledMessageRepository;
31
32
    private Registry $workflowRegistry;
33
34
    private ManagerRegistry $managerRegistry;
35
36 2
    public function __construct(
37
        MessageBusInterface $commandBus,
38
        ScheduledMessageRepositoryInterface $scheduledMessageRepository,
39
        Registry $workflowRegistry,
40
        ManagerRegistry $managerRegistry
41
    ) {
42 2
        $this->logger = new NullLogger();
43 2
        $this->commandBus = $commandBus;
44 2
        $this->scheduledMessageRepository = $scheduledMessageRepository;
45 2
        $this->workflowRegistry = $workflowRegistry;
46 2
        $this->managerRegistry = $managerRegistry;
47 2
    }
48
49 1
    public function dispatch(): void
50
    {
51 1
        $messages = $this->scheduledMessageRepository->findDispatchable();
52
53 1
        if (count($messages) === 0) {
54
            $this->logger->info('No scheduled message are eligible to be dispatched');
55
56
            return;
57
        }
58
59 1
        $workflow = $this->getWorkflow($messages);
60 1
        $objectManager = $this->getObjectManager($messages);
61
62 1
        foreach ($messages as $message) {
63 1
            if (!$workflow->can($message, ScheduledMessageWorkflow::TRANSITION_DISPATCH)) {
64
                $this->logger->info(sprintf(
65
                    'Scheduled message with id, %s, could not be dispatched because it was blocked in the transition',
66
                    $message->getId()
67
                ));
68
69
                continue;
70
            }
71
72 1
            $workflow->apply($message, ScheduledMessageWorkflow::TRANSITION_DISPATCH);
73 1
            $objectManager->flush();
74
75 1
            $this->commandBus->dispatch(new DispatchScheduledMessage($message));
76
77 1
            $this->logger->info(sprintf('Dispatched scheduled message with id: %s', $message->getId()));
78
        }
79 1
    }
80
81
    /**
82
     * This method presumes that all the objects are of the same class
83
     * therefore it returns the workflow for the first object
84
     *
85
     * @param object[] $objects
86
     */
87 1
    private function getWorkflow(array $objects): Workflow
88
    {
89 1
        $obj = current($objects);
90 1
        if (false === $obj) {
91
            throw new LogicException('An empty array of objects were passed to this method');
92
        }
93
94 1
        return $this->workflowRegistry->get($obj, ScheduledMessageWorkflow::NAME);
95
    }
96
97
    /**
98
     * This method presumes that all the objects are of the same class
99
     * therefore it returns the object manager for the first object's class
100
     *
101
     * @param object[] $objects
102
     */
103 1
    private function getObjectManager(array $objects): ObjectManager
104
    {
105 1
        if (null === $this->objectManager) {
106 1
            $obj = current($objects);
107 1
            if (false === $obj) {
108
                throw new LogicException('An empty array of objects were passed to this method');
109
            }
110
111 1
            $class = get_class($obj);
112 1
            $manager = $this->managerRegistry->getManagerForClass($class);
113
114 1
            if (null === $manager) {
115
                throw new RuntimeException(sprintf('No object manager associated with the class, %s', $class));
116
            }
117
118 1
            $this->objectManager = $manager;
119
        }
120
121 1
        return $this->objectManager;
122
    }
123
124
    public function setLogger(LoggerInterface $logger): void
125
    {
126
        $this->logger = $logger;
127
    }
128
}
129