ScheduleRunner::runTask()   A
last analyzed

Complexity

Conditions 3
Paths 5

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 10
cc 3
nc 5
nop 1
crap 3
1
<?php
2
3
namespace Zenstruck\ScheduleBundle\Schedule;
4
5
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
6
use Zenstruck\ScheduleBundle\Event\AfterScheduleEvent;
7
use Zenstruck\ScheduleBundle\Event\AfterTaskEvent;
8
use Zenstruck\ScheduleBundle\Event\BeforeScheduleEvent;
9
use Zenstruck\ScheduleBundle\Event\BeforeTaskEvent;
10
use Zenstruck\ScheduleBundle\Event\BuildScheduleEvent;
11
use Zenstruck\ScheduleBundle\Schedule;
12
use Zenstruck\ScheduleBundle\Schedule\Exception\MissingDependency;
13
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipSchedule;
14
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipTask;
15
use Zenstruck\ScheduleBundle\Schedule\Extension\ExtensionHandlerRegistry;
16
use Zenstruck\ScheduleBundle\Schedule\Task\Result;
17
use Zenstruck\ScheduleBundle\Schedule\Task\TaskRunContext;
18
use Zenstruck\ScheduleBundle\Schedule\Task\TaskRunner;
19
20
/**
21
 * @author Kevin Bond <[email protected]>
22
 */
23
final class ScheduleRunner
24
{
25
    /** @var iterable<TaskRunner> */
26
    private $taskRunners;
27
28
    /** @var ExtensionHandlerRegistry */
29 104
    private $extensions;
30
31 104
    /** @var EventDispatcherInterface */
32 104
    private $dispatcher;
33 104
34 104
    /**
35
     * @param iterable<TaskRunner> $taskRunners
36
     */
37
    public function __construct(iterable $taskRunners, ExtensionHandlerRegistry $handlerRegistry, EventDispatcherInterface $dispatcher)
38
    {
39 84
        $this->taskRunners = $taskRunners;
40
        $this->extensions = $handlerRegistry;
41 84
        $this->dispatcher = $dispatcher;
42
    }
43
44 81
    /**
45 81
     * @param string ...$taskIds Task ID's to force run
46 9
     */
47 7
    public function __invoke(string ...$taskIds): ScheduleRunContext
48
    {
49 7
        $scheduleRunContext = $this->createRunContext($taskIds);
50
51 7
        try {
52
            $this->dispatcher->dispatch(new BeforeScheduleEvent($scheduleRunContext));
53
            $this->extensions->beforeSchedule($scheduleRunContext);
54 72
        } catch (SkipSchedule $e) {
55
            $scheduleRunContext->skip($e);
56 72
57 63
            $this->dispatcher->dispatch(new AfterScheduleEvent($scheduleRunContext));
58
59 63
            return $scheduleRunContext;
60
        }
61 63
62
        $taskRunContexts = [];
63 63
64
        foreach ($scheduleRunContext->dueTasks() as $task) {
65 63
            $taskRunContext = new TaskRunContext($scheduleRunContext, $task);
66
67 63
            $this->dispatcher->dispatch(new BeforeTaskEvent($taskRunContext));
68
69
            $taskRunContext->setResult($this->runTask($taskRunContext));
70 72
71
            $this->postRun($taskRunContext);
72 72
73 72
            $this->dispatcher->dispatch(new AfterTaskEvent($taskRunContext));
74
75 72
            $taskRunContexts[] = $taskRunContext;
76
        }
77
78 104
        $scheduleRunContext->setTaskRunContexts(...$taskRunContexts);
79
80 104
        $this->extensions->afterSchedule($scheduleRunContext);
81
        $this->dispatcher->dispatch(new AfterScheduleEvent($scheduleRunContext));
82 103
83
        return $scheduleRunContext;
84
    }
85 61
86
    public function buildSchedule(): Schedule
87 61
    {
88 61
        $this->dispatcher->dispatch(new BuildScheduleEvent($schedule = new Schedule()));
89 56
90
        return $schedule;
91
    }
92
93 5
    public function runnerFor(Task $task): TaskRunner
94
    {
95
        foreach ($this->taskRunners as $runner) {
96 63
            if ($runner->supports($task)) {
97
                return $runner;
98 63
            }
99
        }
100
101 63
        throw MissingDependency::noTaskRunner($task);
102
    }
103 52
104 22
    private function runTask(TaskRunContext $context): Result
105 11
    {
106 11
        $task = $context->getTask();
107 11
108
        try {
109
            $this->extensions->beforeTask($context);
110
111 63
            return $this->runnerFor($task)($task);
112
        } catch (SkipTask $e) {
113
            return $e->createResult($task);
114 63
        } catch (\Throwable $e) {
115 1
            return Result::exception($task, $e);
116 1
        }
117
    }
118 63
119
    private function postRun(TaskRunContext $context): void
120 84
    {
121
        try {
122 84
            $this->extensions->afterTask($context);
123
        } catch (\Throwable $e) {
124
            $context->setResult(Result::exception($context->getTask(), $e));
125 5
        }
126 83
    }
127
128 81
    /**
129
     * @param string[] $taskIds
130
     */
131
    private function createRunContext(array $taskIds): ScheduleRunContext
132
    {
133
        $schedule = $this->buildSchedule();
134
135
        $tasks = \array_map(function(string $id) use ($schedule) {
136
            return $schedule->getTask($id);
137
        }, $taskIds);
138
139
        return new ScheduleRunContext($schedule, ...$tasks);
140
    }
141
}
142