ConsoleTasker   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 60
c 2
b 0
f 0
dl 0
loc 184
ccs 0
cts 65
cp 0
rs 10
wmc 26

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A rollbackTasksDueTo() 0 18 5
A resolveTask() 0 19 3
A processTask() 0 17 3
A rollbackTask() 0 6 2
A runTasks() 0 22 6
A handleFailedTask() 0 8 3
A runTask() 0 12 3
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
        $summary = Summary::instance();
48
49
        $this->newLine();
50
51
        try {
52
            foreach ($tasks as $class) {
53
                $this->processTask($this->resolveTask($class));
54
            }
55
        } catch (Throwable $e) {
56
            $e = $e instanceof StoppingTaskException ? null : $e;
57
        }
58
59
        $this->printer->printSummary();
60
61
        $exception = $summary->getFirstException() ?: $e ?? null;
62
63
        $summary->clear();
64
65
        if ($exception) {
66
            throw $exception;
67
        }
68
    }
69
70
    /**
71
     * Retrieve the resolved instance of the given task class
72
     *
73
     * @param string $class
74
     * @return AbstractTask
75
     */
76
    protected function resolveTask(string $class): AbstractTask
77
    {
78
        $invalidTask = new InvalidTask($class);
79
80
        try {
81
            $task = Container::getInstance()->make($class);
82
            $valid = $task instanceof AbstractTask;
83
        } catch (Throwable $e) {
84
            $invalidTask->setException($e);
85
            $valid = false;
86
        }
87
88
        if ($valid) {
89
            return $task->setIO($this->input, $this->output);
90
        }
91
92
        Summary::instance()->addInvalidTask($invalidTask);
93
94
        return $invalidTask;
95
    }
96
97
    /**
98
     * Process the given task
99
     *
100
     * @param AbstractTask $task
101
     * @return bool
102
     * @throws Throwable
103
     */
104
    protected function processTask(AbstractTask $task): bool
105
    {
106
        $this->printer->printRunningTask($task, function (AbstractTask $task) {
107
            $this->runTask($task);
108
        });
109
110
        if (!$task->shouldRun()) {
111
            return false;
112
        }
113
114
        Summary::instance()->addExecutedTask($task);
115
116
        if (!$task->succeeded()) {
117
            $this->handleFailedTask($task);
118
        }
119
120
        return $task->succeeded();
121
    }
122
123
    /**
124
     * Run the given task
125
     *
126
     * @param AbstractTask $task
127
     * @return void
128
     */
129
    protected function runTask(AbstractTask $task): void
130
    {
131
        if (!$task->shouldRun()) {
132
            return;
133
        }
134
135
        try {
136
            $task->setResult($task->run() !== false);
137
        } catch (Throwable $e) {
138
            $task->setException($e);
139
            $task->setError($e->getMessage());
140
            $task->setResult(false);
141
        }
142
    }
143
144
    /**
145
     * Handle the given failed task
146
     *
147
     * @param AbstractTask $task
148
     * @return void
149
     * @throws Throwable
150
     */
151
    protected function handleFailedTask(AbstractTask $task): void
152
    {
153
        $succeededTasks = Summary::instance()->getSucceededTasks();
154
155
        $this->rollbackTasksDueTo($succeededTasks, $task);
156
157
        if ($task->stopsSuccessiveTasksOnFailure()) {
158
            throw $task->getException() ?: new StoppingTaskException($task);
159
        }
160
    }
161
162
    /**
163
     * Rollback the given tasks due to the provided failed task
164
     *
165
     * @param AbstractTask[] $tasks
166
     * @param AbstractTask $failedTask
167
     * @return void
168
     */
169
    protected function rollbackTasksDueTo(array $tasks, AbstractTask $failedTask): void
170
    {
171
        if (empty($tasks)) {
172
            return;
173
        }
174
175
        $task = array_pop($tasks);
176
177
        if (!$task->ranRollback() && $task->shouldRollbackDueTo($failedTask)) {
178
            $this->rollbackTask($task);
179
            Summary::instance()->addRolledbackTask($task, $failedTask);
180
181
            if ($task->rolledback()) {
182
                $this->rollbackTasksDueTo($tasks, $task);
183
            }
184
        }
185
186
        $this->rollbackTasksDueTo($tasks, $failedTask);
187
    }
188
189
    /**
190
     * Rollback the given task
191
     *
192
     * @param AbstractTask $task
193
     * @return void
194
     */
195
    protected function rollbackTask(AbstractTask $task): void
196
    {
197
        try {
198
            $task->rollback();
199
        } catch (Throwable $e) {
200
            $task->setRollbackException($e);
201
        }
202
    }
203
}
204