Passed
Push — master ( 9213a8...e174b6 )
by Kevin
02:14
created

ScheduleRunner   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 14
eloc 50
c 1
b 0
f 0
dl 0
loc 106
ccs 51
cts 51
cp 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A postRun() 0 6 2
A __invoke() 0 37 3
A runnerFor() 0 9 3
A buildSchedule() 0 5 1
A createRunContext() 0 9 1
A runTask() 0 12 3
A __construct() 0 5 1
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\SkipSchedule;
13
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipTask;
14
use Zenstruck\ScheduleBundle\Schedule\Extension\ExtensionHandlerRegistry;
15
use Zenstruck\ScheduleBundle\Schedule\Task\Result;
16
use Zenstruck\ScheduleBundle\Schedule\Task\TaskRunContext;
17
use Zenstruck\ScheduleBundle\Schedule\Task\TaskRunner;
18
19
/**
20
 * @author Kevin Bond <[email protected]>
21
 */
22
final class ScheduleRunner
23
{
24
    private $taskRunners;
25
    private $extensions;
26
    private $dispatcher;
27
28 62
    public function __construct(iterable $taskRunners, ExtensionHandlerRegistry $handlerRegistry, EventDispatcherInterface $dispatcher)
29
    {
30 62
        $this->taskRunners = $taskRunners;
31 62
        $this->extensions = $handlerRegistry;
32 62
        $this->dispatcher = $dispatcher;
33 62
    }
34
35
    /**
36
     * @param string ...$taskIds Task ID's to force run
37
     */
38 42
    public function __invoke(string ...$taskIds): ScheduleRunContext
39
    {
40 42
        $scheduleRunContext = $this->createRunContext($taskIds);
41
42
        try {
43 39
            $this->dispatcher->dispatch(new BeforeScheduleEvent($scheduleRunContext));
44 39
            $this->extensions->beforeSchedule($scheduleRunContext);
45 5
        } catch (SkipSchedule $e) {
46 3
            $scheduleRunContext->skip($e);
47
48 3
            $this->dispatcher->dispatch(new AfterScheduleEvent($scheduleRunContext));
49
50 3
            return $scheduleRunContext;
51
        }
52
53 34
        $results = [];
54
55 34
        foreach ($scheduleRunContext->dueTasks() as $task) {
56 30
            $taskRunContext = new TaskRunContext($scheduleRunContext, $task);
57
58 30
            $this->dispatcher->dispatch(new BeforeTaskEvent($taskRunContext));
59
60 30
            $taskRunContext->setResult($this->runTask($taskRunContext));
61
62 30
            $this->postRun($taskRunContext);
63
64 30
            $this->dispatcher->dispatch(new AfterTaskEvent($taskRunContext));
65
66 30
            $results[] = $taskRunContext->result();
67
        }
68
69 34
        $scheduleRunContext->setResults(...$results);
70
71 34
        $this->extensions->afterSchedule($scheduleRunContext);
72 34
        $this->dispatcher->dispatch(new AfterScheduleEvent($scheduleRunContext));
73
74 34
        return $scheduleRunContext;
75
    }
76
77 62
    public function buildSchedule(): Schedule
78
    {
79 62
        $this->dispatcher->dispatch(new BuildScheduleEvent($schedule = new Schedule()));
80
81 61
        return $schedule;
82
    }
83
84 38
    public function runnerFor(Task $task): TaskRunner
85
    {
86 38
        foreach ($this->taskRunners as $runner) {
87 38
            if ($runner->supports($task)) {
88 34
                return $runner;
89
            }
90
        }
91
92 4
        throw new \LogicException(\sprintf('No task runner registered to handle "%s".', \get_class($task)));
93
    }
94
95 30
    private function runTask(TaskRunContext $context): Result
96
    {
97 30
        $task = $context->task();
98
99
        try {
100 30
            $this->extensions->beforeTask($context);
101
102 29
            return $this->runnerFor($task)($task);
103 3
        } catch (SkipTask $e) {
104 1
            return $e->createResult($task);
105 2
        } catch (\Throwable $e) {
106 2
            return Result::exception($task, $e);
107
        }
108
    }
109
110 30
    private function postRun(TaskRunContext $context): void
111
    {
112
        try {
113 30
            $this->extensions->afterTask($context);
114 1
        } catch (\Throwable $e) {
115 1
            $context->setResult(Result::exception($context->task(), $e));
116
        }
117 30
    }
118
119 42
    private function createRunContext(array $taskIds): ScheduleRunContext
120
    {
121 42
        $schedule = $this->buildSchedule();
122
123
        $tasks = \array_map(function (string $id) use ($schedule) {
124 5
            return $schedule->getTask($id);
125 41
        }, $taskIds);
126
127 39
        return new ScheduleRunContext($schedule, ...$tasks);
128
    }
129
}
130