Passed
Push — master ( 32dee0...5d2de3 )
by Andrea Marco
13:08 queued 11s
created

ConsoleTasker::resolveTask()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 11
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 19
ccs 0
cts 12
cp 0
crap 12
rs 9.9
1
<?php
2
3
namespace Cerbero\ConsoleTasker;
4
5
use Cerbero\ConsoleTasker\Console\Printers\PrinterInterface;
6
use Cerbero\ConsoleTasker\Exceptions\StoppingTaskException;
7
use Cerbero\ConsoleTasker\Tasks\AbstractTask;
8
use Cerbero\ConsoleTasker\Tasks\InvalidTask;
9
use Cerbero\ConsoleTasker\Traits\IOAware;
10
use Illuminate\Container\Container;
11
use Throwable;
12
13
/**
14
 * The console tasker.
15
 *
16
 */
17
class ConsoleTasker
18
{
19
    use IOAware;
20
21
    /**
22
     * The console printer.
23
     *
24
     * @var PrinterInterface
25
     */
26
    protected $printer;
27
28
    /**
29
     * Instantiate the class.
30
     *
31
     * @param PrinterInterface $printer
32
     */
33
    public function __construct(PrinterInterface $printer)
34
    {
35
        $this->printer = $printer;
36
    }
37
38
    /**
39
     * Run the given tasks
40
     *
41
     * @param iterable $tasks
42
     * @return void
43
     * @throws Throwable
44
     */
45
    public function runTasks(iterable $tasks): void
46
    {
47
        try {
48
            foreach ($tasks as $class) {
49
                $this->processTask($this->resolveTask($class));
50
            }
51
        } catch (Throwable $e) {
52
            // catch exception to throw later
53
        }
54
55
        $this->printer->printSummary();
56
57
        if ($exception = Summary::instance()->getFirstException() ?: $e ?? null) {
58
            throw $exception;
59
        }
60
    }
61
62
    /**
63
     * Retrieve the resolved instance of the given task class
64
     *
65
     * @param string $class
66
     * @return AbstractTask
67
     */
68
    protected function resolveTask(string $class): AbstractTask
69
    {
70
        $invalidTask = new InvalidTask($class);
71
72
        try {
73
            $task = Container::getInstance()->make($class)->setIO($this->input, $this->output);
74
            $valid = $task instanceof AbstractTask;
75
        } catch (Throwable $e) {
76
            $invalidTask->setException($e);
77
            $valid = false;
78
        }
79
80
        if ($valid) {
81
            return $task;
82
        }
83
84
        Summary::instance()->addInvalidTask($invalidTask);
85
86
        return $invalidTask;
87
    }
88
89
    /**
90
     * Process the given task
91
     *
92
     * @param AbstractTask $task
93
     * @return bool
94
     * @throws Throwable
95
     */
96
    protected function processTask(AbstractTask $task): bool
97
    {
98
        $this->printer->printRunningTask($task, function (AbstractTask $task) {
99
            $this->runTask($task);
100
        });
101
102
        if (!$task->shouldRun()) {
103
            return false;
104
        }
105
106
        Summary::instance()->addExecutedTask($task);
107
108
        if (!$task->succeeded()) {
109
            $this->handleFailedTask($task);
110
        }
111
112
        return $task->succeeded();
113
    }
114
115
    /**
116
     * Run the given task
117
     *
118
     * @param AbstractTask $task
119
     * @return void
120
     */
121
    protected function runTask(AbstractTask $task): void
122
    {
123
        if (!$task->shouldRun()) {
124
            return;
125
        }
126
127
        try {
128
            $task->setResult($task->run() !== false);
129
        } catch (Throwable $e) {
130
            $task->setException($e);
131
            $task->setError($e->getMessage());
132
            $task->setResult(false);
133
        }
134
    }
135
136
    /**
137
     * Handle the given failed task
138
     *
139
     * @param AbstractTask $task
140
     * @return void
141
     * @throws Throwable
142
     */
143
    protected function handleFailedTask(AbstractTask $task): void
144
    {
145
        $succeededTasks = Summary::instance()->getSucceededTasks();
146
147
        $this->rollbackTasksDueTo($succeededTasks, $task);
148
149
        if ($task->stopsSuccessiveTasksOnFailure()) {
150
            throw $task->getException() ?: new StoppingTaskException($task);
151
        }
152
    }
153
154
    /**
155
     * Rollback the given tasks due to the provided failed task
156
     *
157
     * @param AbstractTask[] $tasks
158
     * @param AbstractTask $failedTask
159
     * @return void
160
     */
161
    protected function rollbackTasksDueTo(array $tasks, AbstractTask $failedTask): void
162
    {
163
        if (empty($tasks)) {
164
            return;
165
        }
166
167
        $task = array_pop($tasks);
168
169
        if (!$task->ranRollback() && $task->shouldRollbackDueTo($failedTask)) {
170
            $this->rollbackTask($task);
171
            Summary::instance()->addRolledbackTask($task, $failedTask);
172
173
            if ($task->rolledback()) {
174
                $this->rollbackTasksDueTo($tasks, $task);
175
            }
176
        }
177
178
        $this->rollbackTasksDueTo($tasks, $failedTask);
179
    }
180
181
    /**
182
     * Rollback the given task
183
     *
184
     * @param AbstractTask $task
185
     * @return void
186
     */
187
    protected function rollbackTask(AbstractTask $task): void
188
    {
189
        try {
190
            $task->rollback();
191
        } catch (Throwable $e) {
192
            $task->setRollbackException($e);
193
        }
194
    }
195
}
196