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\Database\Exception; |
9
|
|
|
use Tworzenieweb\SqlProvisioner\Database\Executor; |
10
|
|
|
use Tworzenieweb\SqlProvisioner\Formatter\Sql; |
11
|
|
|
use Tworzenieweb\SqlProvisioner\Model\Candidate; |
12
|
|
|
use Tworzenieweb\SqlProvisioner\Processor\CandidateProcessor; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Class ActionDispatcher |
16
|
|
|
* |
17
|
|
|
* @package Tworzenieweb\SqlProvisioner\Controller |
18
|
|
|
*/ |
19
|
|
|
class ProvisionDispatcher |
20
|
|
|
{ |
21
|
|
|
/** @var Executor */ |
22
|
|
|
private $executor; |
23
|
|
|
|
24
|
|
|
/** @var CandidateProcessor */ |
25
|
|
|
private $processor; |
26
|
|
|
|
27
|
|
|
/** @var HasSyntaxCorrectCheck */ |
28
|
|
|
private $syntaxCheck; |
29
|
|
|
|
30
|
|
|
/** @var Sql */ |
31
|
|
|
private $sqlFormatter; |
32
|
|
|
|
33
|
|
|
/** @var SymfonyStyle */ |
34
|
|
|
private $input; |
35
|
|
|
|
36
|
|
|
/** @var int */ |
37
|
|
|
private $startTimestamp; |
38
|
|
|
|
39
|
|
|
/** @var int */ |
40
|
|
|
private $candidateIndexValue = 1; |
41
|
|
|
|
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* ActionDispatcher constructor. |
45
|
|
|
* |
46
|
|
|
* @param Executor $executor |
47
|
|
|
* @param CandidateProcessor $processor |
48
|
|
|
* @param HasSyntaxCorrectCheck $check |
49
|
|
|
* @param Sql $sqlFormatter |
50
|
|
|
*/ |
51
|
|
|
public function __construct( |
52
|
|
|
Executor $executor, |
53
|
|
|
CandidateProcessor $processor, |
54
|
|
|
HasSyntaxCorrectCheck $check, |
55
|
|
|
Sql $sqlFormatter |
56
|
|
|
) { |
57
|
|
|
$this->executor = $executor; |
58
|
|
|
$this->processor = $processor; |
59
|
|
|
$this->syntaxCheck = $check; |
60
|
|
|
$this->sqlFormatter = $sqlFormatter; |
61
|
|
|
$this->startTimestamp = time(); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
|
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @param SymfonyStyle $io |
68
|
|
|
*/ |
69
|
|
|
public function setInputOutput(SymfonyStyle $io) |
70
|
|
|
{ |
71
|
|
|
$this->input = $io; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
|
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @param Candidate[] $workingDirectoryCandidates |
78
|
|
|
* @param int $queuedCandidatesCount |
79
|
|
|
*/ |
80
|
|
|
public function deploy(array $workingDirectoryCandidates, $queuedCandidatesCount) |
81
|
|
|
{ |
82
|
|
|
while (!empty($workingDirectoryCandidates)) { |
83
|
|
|
$candidate = array_shift($workingDirectoryCandidates); |
84
|
|
|
|
85
|
|
|
if ($candidate->isQueued()) { |
86
|
|
|
$this->executeCandidateScript($candidate, $queuedCandidatesCount); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
$this->input->writeln('<info>All candidates scripts were executed</info>'); |
90
|
|
|
$this->finalizeAndExit(); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
|
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @param Candidate $candidate |
97
|
|
|
*/ |
98
|
|
|
public function validate(Candidate $candidate) |
99
|
|
|
{ |
100
|
|
|
if ($this->processor->isValid($candidate)) { |
101
|
|
|
$candidate->markAsQueued(); |
102
|
|
|
$candidate->setIndex($this->candidateIndexValue++); |
103
|
|
|
|
104
|
|
|
return; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$this->ignoreCandidateHavingError($candidate); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
|
111
|
|
|
public function skipSyntaxCheck() |
112
|
|
|
{ |
113
|
|
|
$this->input->warning('SQL parsing disabled. This could lead to executing invalid queries.'); |
114
|
|
|
$this->processor->removeCheck($this->syntaxCheck); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
|
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @param Candidate $candidate |
121
|
|
|
*/ |
122
|
|
|
private function ignoreCandidateHavingError(Candidate $candidate) |
123
|
|
|
{ |
124
|
|
|
$candidate->markAsIgnored($this->processor->getLastError()); |
125
|
|
|
$lastErrorMessage = $this->processor->getLastErrorMessage(); |
126
|
|
|
|
127
|
|
|
if (null !== $lastErrorMessage) { |
128
|
|
|
throw new RuntimeException($lastErrorMessage); |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
|
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @param Candidate $candidate |
136
|
|
|
* @param int $queuedCandidatesCount |
137
|
|
|
*/ |
138
|
|
|
private function executeCandidateScript(Candidate $candidate, $queuedCandidatesCount) |
139
|
|
|
{ |
140
|
|
|
if ($candidate->isQueued()) { |
141
|
|
|
$this->input->warning( |
142
|
|
|
sprintf( |
143
|
|
|
'PROCESSING [%d/%d] %s', |
144
|
|
|
$candidate->getIndex(), |
145
|
|
|
$queuedCandidatesCount, |
146
|
|
|
$candidate->getName() |
147
|
|
|
) |
148
|
|
|
); |
149
|
|
|
$this->input->text($this->sqlFormatter->format($candidate->getContent())); |
150
|
|
|
$action = $this->input->choice( |
151
|
|
|
sprintf('What action to perform for "%s"', $candidate->getName()), |
152
|
|
|
['DEPLOY', 'SKIP', 'QUIT'] |
153
|
|
|
); |
154
|
|
|
|
155
|
|
|
switch ($action) { |
156
|
|
|
case 'DEPLOY': |
157
|
|
|
$this->deployCandidate($candidate); |
158
|
|
|
break; |
159
|
|
|
case 'QUIT': |
160
|
|
|
$this->finalizeAndExit(); |
161
|
|
|
break; |
162
|
|
|
} |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
|
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param Candidate $candidate |
170
|
|
|
*/ |
171
|
|
|
private function deployCandidate(Candidate $candidate) |
172
|
|
|
{ |
173
|
|
|
try { |
174
|
|
|
$this->executor->execute($candidate); |
175
|
|
|
$this->processor->postValidate($candidate); |
176
|
|
|
} catch (Exception $databaseException) { |
177
|
|
|
$this->input->error($databaseException->getMessage()); |
178
|
|
|
$this->input->writeln( |
179
|
|
|
sprintf( |
180
|
|
|
"<bg=yellow>%s\n\r%s</>", |
181
|
|
|
$databaseException->getPrevious()->getMessage(), |
182
|
|
|
$candidate->getContent() |
183
|
|
|
) |
184
|
|
|
); |
185
|
|
|
$this->terminate(); |
186
|
|
|
} catch (RuntimeException $runtimeException) { |
187
|
|
|
$this->input->error($runtimeException->getMessage()); |
188
|
|
|
$this->terminate(); |
189
|
|
|
} |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
|
193
|
|
|
|
194
|
|
|
public function finalizeAndExit() |
195
|
|
|
{ |
196
|
|
|
$this->input->text(sprintf('Provisioning ended at %s', date('Y-m-d H:i:s'))); |
197
|
|
|
$this->input->writeln(str_repeat('=', 120)); |
198
|
|
|
$this->input->writeln( |
199
|
|
|
sprintf( |
200
|
|
|
'<info>Memory used: %s MB. Total Time of provisioning: %s seconds</info>', |
201
|
|
|
memory_get_peak_usage(true) / (pow(1024, 2)), |
202
|
|
|
time() - $this->startTimestamp |
203
|
|
|
) |
204
|
|
|
); |
205
|
|
|
die(0); |
|
|
|
|
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
|
209
|
|
|
|
210
|
|
|
private function terminate() |
211
|
|
|
{ |
212
|
|
|
$this->input->text(sprintf('Provisioning ended with error at %s', date('Y-m-d H:i:s'))); |
213
|
|
|
die(1); |
214
|
|
|
} |
215
|
|
|
} |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.