ProvisionDispatcher   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 7.61%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 7
dl 0
loc 219
rs 10
c 0
b 0
f 0
ccs 7
cts 92
cp 0.0761

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A setInputOutput() 0 4 1
A deploy() 0 12 3
A validate() 0 11 2
A skipSyntaxCheck() 0 5 1
A ignoreCandidateHavingError() 0 9 2
A executeCandidateScript() 0 20 2
A deployCandidate() 0 20 3
A finalizeAndExit() 0 13 1
A terminate() 0 5 1
A dispatchAction() 0 11 3
1
<?php
2
3
namespace Tworzenieweb\SqlProvisioner\Controller;
4
5
use RuntimeException;
6
use Symfony\Component\Console\Style\SymfonyStyle;
7
use Tworzenieweb\SqlProvisioner\Check\HasSyntaxCorrectCheck;
8
use Tworzenieweb\SqlProvisioner\Config\ProvisionConfig;
9
use Tworzenieweb\SqlProvisioner\Database\Exception;
10
use Tworzenieweb\SqlProvisioner\Database\Executor;
11
use Tworzenieweb\SqlProvisioner\Formatter\Sql;
12
use Tworzenieweb\SqlProvisioner\Model\Candidate;
13
use Tworzenieweb\SqlProvisioner\Processor\CandidateProcessor;
14
15
/**
16
 * Class ActionDispatcher
17
 *
18
 * @package Tworzenieweb\SqlProvisioner\Controller
19
 */
20
class ProvisionDispatcher
21
{
22
    const ACTION_DEPLOY = 'DEPLOY';
23
    const ACTION_SKIP = 'SKIP';
24
    const ACTION_QUIT = 'QUIT';
25
26
    /** @var Executor */
27
    private $executor;
28
29
    /** @var CandidateProcessor */
30
    private $processor;
31
32
    /** @var HasSyntaxCorrectCheck */
33
    private $syntaxCheck;
34
35
    /** @var Sql */
36
    private $sqlFormatter;
37
38
    /** @var ProvisionConfig */
39
    private $config;
40
41
    /** @var SymfonyStyle */
42
    private $input;
43
44
    /** @var int */
45
    private $startTimestamp;
46
47
    /** @var int */
48
    private $candidateIndexValue = 1;
49
50
51
    /**
52
     * ActionDispatcher constructor.
53
     *
54
     * @param Executor              $executor
55
     * @param CandidateProcessor    $processor
56 1
     * @param HasSyntaxCorrectCheck $check
57
     * @param Sql                   $sqlFormatter
58
     * @param ProvisionConfig       $config
59
     */
60
    public function __construct(
61
        Executor $executor,
62 1
        CandidateProcessor $processor,
63 1
        HasSyntaxCorrectCheck $check,
64 1
        Sql $sqlFormatter,
65 1
        ProvisionConfig $config
66 1
    ) {
67 1
        $this->executor       = $executor;
68
        $this->processor      = $processor;
69
        $this->syntaxCheck    = $check;
70
        $this->sqlFormatter   = $sqlFormatter;
71
        $this->config         = $config;
72
        $this->startTimestamp = time();
73
    }
74
75
76
77
    /**
78
     * @param SymfonyStyle $io
79
     */
80
    public function setInputOutput(SymfonyStyle $io)
81
    {
82
        $this->input = $io;
83
    }
84
85
86
87
    /**
88
     * @param Candidate[] $workingDirectoryCandidates
89
     * @param int         $queuedCandidatesCount
90
     */
91
    public function deploy(array $workingDirectoryCandidates, $queuedCandidatesCount)
92
    {
93
        while (!empty($workingDirectoryCandidates)) {
94
            $candidate = array_shift($workingDirectoryCandidates);
95
96
            if ($candidate->isQueued()) {
97
                $this->executeCandidateScript($candidate, $queuedCandidatesCount);
98
            }
99
        }
100
        $this->input->writeln('<info>All candidates scripts were executed</info>');
101
        $this->finalizeAndExit();
102
    }
103
104
105
106
    /**
107
     * @param Candidate $candidate
108
     */
109
    public function validate(Candidate $candidate)
110
    {
111
        if ($this->processor->isValid($candidate)) {
112
            $candidate->markAsQueued();
113
            $candidate->setIndex($this->candidateIndexValue++);
114
115
            return;
116
        }
117
118
        $this->ignoreCandidateHavingError($candidate);
119
    }
120
121
122
123
    public function skipSyntaxCheck()
124
    {
125
        $this->input->warning('SQL parsing disabled. This could lead to executing invalid queries.');
126
        $this->processor->removeCheck($this->syntaxCheck);
127
    }
128
129
130
131
    /**
132
     * @param Candidate $candidate
133
     */
134
    private function ignoreCandidateHavingError(Candidate $candidate)
135
    {
136
        $candidate->markAsIgnored($this->processor->getLastError());
137
        $lastErrorMessage = $this->processor->getLastErrorMessage();
138
139
        if (null !== $lastErrorMessage) {
140
            throw new RuntimeException($lastErrorMessage);
141
        }
142
    }
143
144
145
146
    /**
147
     * @param Candidate $candidate
148
     * @param int $queuedCandidatesCount
149
     */
150
    private function executeCandidateScript(Candidate $candidate, $queuedCandidatesCount)
151
    {
152
        $this->input->warning(
153
            sprintf(
154
                'PROCESSING [%d/%d] %s',
155
                $candidate->getIndex(),
156
                $queuedCandidatesCount,
157
                $candidate->getName()
158
            )
159
        );
160
        $this->input->text($this->sqlFormatter->format($candidate->getContent()));
161
        $action = $this->config->isForce()
162
            ? self::ACTION_DEPLOY
163
            : $this->input->choice(
164
            sprintf('What action to perform for "%s"', $candidate->getName()),
165
            [self::ACTION_DEPLOY, self::ACTION_SKIP, self::ACTION_QUIT]
166
        );
167
168
        $this->dispatchAction($candidate, $action);
169
    }
170
171
172
173
    /**
174
     * @param Candidate $candidate
175
     */
176
    private function deployCandidate(Candidate $candidate)
177
    {
178
        try {
179
            $this->executor->execute($candidate);
180
            $this->processor->postValidate($candidate);
181
        } catch (Exception $databaseException) {
182
            $this->input->error($databaseException->getMessage());
183
            $this->input->writeln(
184
                sprintf(
185
                    "<bg=yellow>%s\n\r%s</>",
186
                    $databaseException->getPrevious()->getMessage(),
187
                    $candidate->getContent()
188
                )
189
            );
190
            $this->terminate();
191
        } catch (RuntimeException $runtimeException) {
192
            $this->input->error($runtimeException->getMessage());
193
            $this->terminate();
194
        }
195
    }
196
197
198
199
    public function finalizeAndExit()
200
    {
201
        $this->input->text(sprintf('Provisioning ended at %s', date('Y-m-d H:i:s')));
202
        $this->input->writeln(str_repeat('=', 120));
203
        $this->input->writeln(
204
            sprintf(
205
                '<info>Memory used: %s MB. Total Time of provisioning: %s seconds</info>',
206
                memory_get_peak_usage(true) / (pow(1024, 2)),
207
                time() - $this->startTimestamp
208
            )
209
        );
210
        die(0);
211
    }
212
213
214
215
    private function terminate()
216
    {
217
        $this->input->text(sprintf('Provisioning ended with error at %s', date('Y-m-d H:i:s')));
218
        die(1);
219
    }
220
221
222
223
    /**
224
     * @param Candidate $candidate
225
     * @param string $action
226
     */
227
    private function dispatchAction(Candidate $candidate, $action)
228
    {
229
        switch ($action) {
230
            case self::ACTION_DEPLOY:
231
                $this->deployCandidate($candidate);
232
                break;
233
            case self::ACTION_QUIT:
234
                $this->finalizeAndExit();
235
                break;
236
        }
237
    }
238
}
239