1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Cycle\Migrations\Atomizer; |
||
6 | |||
7 | use Cycle\Database\Schema\AbstractColumn; |
||
0 ignored issues
–
show
|
|||
8 | use Cycle\Database\Schema\AbstractForeignKey; |
||
9 | use Cycle\Database\Schema\AbstractIndex; |
||
10 | use Cycle\Database\Schema\AbstractTable; |
||
11 | use Cycle\Database\Schema\Comparator; |
||
12 | use Spiral\Reactor\Partial\Source; |
||
13 | use Spiral\Reactor\Serializer; |
||
14 | use Spiral\Reactor\Traits\SerializerTrait; |
||
15 | |||
16 | final class Renderer implements RendererInterface |
||
17 | { |
||
18 | use SerializerTrait; |
||
19 | |||
20 | /** |
||
21 | * Comparator alteration states. |
||
22 | */ |
||
23 | public const NEW_STATE = 0; |
||
24 | public const ORIGINAL_STATE = 1; |
||
25 | |||
26 | /** |
||
27 | * {@inheritdoc} |
||
28 | */ |
||
29 | 144 | public function createTable(Source $source, AbstractTable $table): void |
|
30 | { |
||
31 | 144 | $this->render( |
|
32 | $source, |
||
33 | '$this->table(%s)', |
||
34 | $table |
||
35 | ); |
||
36 | 144 | $comparator = $table->getComparator(); |
|
37 | |||
38 | 144 | $this->declareColumns($source, $comparator); |
|
39 | 144 | $this->declareIndexes($source, $comparator); |
|
40 | 144 | $this->declareForeignKeys($source, $comparator, $table->getPrefix()); |
|
41 | |||
42 | 144 | if (count($table->getPrimaryKeys())) { |
|
43 | 136 | $this->render( |
|
44 | $source, |
||
45 | ' ->setPrimaryKeys(%s)', |
||
46 | 136 | $table->getPrimaryKeys() |
|
47 | ); |
||
48 | } |
||
49 | |||
50 | //Finalization |
||
51 | 144 | $source->addLine(' ->create();'); |
|
52 | } |
||
53 | |||
54 | /** |
||
55 | * {@inheritdoc} |
||
56 | */ |
||
57 | 104 | public function updateTable(Source $source, AbstractTable $table): void |
|
58 | { |
||
59 | 104 | $this->render( |
|
60 | $source, |
||
61 | '$this->table(%s)', |
||
62 | $table |
||
63 | ); |
||
64 | 104 | $comparator = $table->getComparator(); |
|
65 | |||
66 | 104 | if ($comparator->isPrimaryChanged()) { |
|
67 | 8 | $this->render( |
|
68 | $source, |
||
69 | ' ->setPrimaryKeys(%s)', |
||
70 | 8 | $table->getPrimaryKeys() |
|
71 | ); |
||
72 | } |
||
73 | |||
74 | 104 | $this->declareColumns($source, $comparator); |
|
75 | 104 | $this->declareIndexes($source, $comparator); |
|
76 | 104 | $this->declareForeignKeys($source, $comparator, $table->getPrefix()); |
|
77 | |||
78 | //Finalization |
||
79 | 104 | $source->addLine(' ->update();'); |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * {@inheritdoc} |
||
84 | */ |
||
85 | 104 | public function revertTable(Source $source, AbstractTable $table): void |
|
86 | { |
||
87 | //Get table blueprint |
||
88 | 104 | $this->render( |
|
89 | $source, |
||
90 | '$this->table(%s)', |
||
91 | $table |
||
92 | ); |
||
93 | 104 | $comparator = $table->getComparator(); |
|
94 | |||
95 | 104 | $this->revertForeignKeys($source, $comparator, $table->getPrefix()); |
|
96 | 104 | $this->revertIndexes($source, $comparator); |
|
97 | 104 | $this->revertColumns($source, $comparator); |
|
98 | |||
99 | //Finalization |
||
100 | 104 | $source->addLine(' ->update();'); |
|
101 | } |
||
102 | |||
103 | /** |
||
104 | * {@inheritdoc} |
||
105 | */ |
||
106 | 144 | public function dropTable(Source $source, AbstractTable $table): void |
|
107 | { |
||
108 | 144 | $this->render( |
|
109 | $source, |
||
110 | '$this->table(%s)->drop();', |
||
111 | $table |
||
112 | ); |
||
113 | } |
||
114 | |||
115 | 144 | private function declareColumns(Source $source, Comparator $comparator): void |
|
116 | { |
||
117 | 144 | foreach ($comparator->addedColumns() as $column) { |
|
118 | 144 | $this->render( |
|
119 | $source, |
||
120 | ' ->addColumn(%s, %s, %s)', |
||
121 | 144 | $column->getName(), |
|
122 | 144 | $column->getDeclaredType() ?? $column->getAbstractType(), |
|
123 | $column |
||
124 | ); |
||
125 | } |
||
126 | |||
127 | 144 | foreach ($comparator->alteredColumns() as $pair) { |
|
128 | 48 | $this->alterColumn( |
|
129 | $source, |
||
130 | 48 | $pair[self::NEW_STATE], |
|
131 | 48 | $pair[self::ORIGINAL_STATE] |
|
132 | ); |
||
133 | } |
||
134 | |||
135 | 144 | foreach ($comparator->droppedColumns() as $column) { |
|
136 | 16 | $this->render( |
|
137 | $source, |
||
138 | ' ->dropColumn(%s)', |
||
139 | 16 | $column->getName() |
|
140 | ); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | 144 | private function declareIndexes(Source $source, Comparator $comparator): void |
|
145 | { |
||
146 | 144 | foreach ($comparator->addedIndexes() as $index) { |
|
147 | 104 | $this->render( |
|
148 | $source, |
||
149 | ' ->addIndex(%s, %s)', |
||
150 | 104 | $index->getColumns(), |
|
151 | $index |
||
152 | ); |
||
153 | } |
||
154 | |||
155 | 144 | foreach ($comparator->alteredIndexes() as $pair) { |
|
156 | /** @var AbstractIndex $index */ |
||
157 | 16 | $index = $pair[self::NEW_STATE]; |
|
158 | 16 | $this->render( |
|
159 | $source, |
||
160 | ' ->alterIndex(%s, %s)', |
||
161 | 16 | $index->getColumns(), |
|
162 | $index |
||
163 | ); |
||
164 | } |
||
165 | |||
166 | 144 | foreach ($comparator->droppedIndexes() as $index) { |
|
167 | 8 | $this->render( |
|
168 | $source, |
||
169 | ' ->dropIndex(%s)', |
||
170 | 8 | $index->getColumns() |
|
171 | ); |
||
172 | } |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * @param string $prefix Database isolation prefix |
||
177 | */ |
||
178 | 144 | private function declareForeignKeys(Source $source, Comparator $comparator, string $prefix = ''): void |
|
179 | { |
||
180 | 144 | foreach ($comparator->addedForeignKeys() as $key) { |
|
181 | 40 | $this->render( |
|
182 | $source, |
||
183 | ' ->addForeignKey(%s, %s, %s, %s)', |
||
184 | 40 | $key->getColumns(), |
|
185 | 40 | substr($key->getForeignTable(), strlen($prefix)), |
|
186 | 40 | $key->getForeignKeys(), |
|
187 | $key |
||
188 | ); |
||
189 | } |
||
190 | |||
191 | 144 | foreach ($comparator->alteredForeignKeys() as $pair) { |
|
192 | /** @var AbstractForeignKey $key */ |
||
193 | 8 | $key = $pair[self::NEW_STATE]; |
|
194 | 8 | $this->render( |
|
195 | $source, |
||
196 | ' ->alterForeignKey(%s, %s, %s, %s)', |
||
197 | 8 | $key->getColumns(), |
|
198 | 8 | substr($key->getForeignTable(), strlen($prefix)), |
|
199 | 8 | $key->getForeignKeys(), |
|
200 | $key |
||
201 | ); |
||
202 | } |
||
203 | |||
204 | 144 | foreach ($comparator->droppedForeignKeys() as $key) { |
|
205 | 8 | $this->render( |
|
206 | $source, |
||
207 | ' ->dropForeignKey(%s)', |
||
208 | 8 | $key->getColumns() |
|
209 | ); |
||
210 | } |
||
211 | } |
||
212 | |||
213 | 104 | private function revertColumns(Source $source, Comparator $comparator): void |
|
214 | { |
||
215 | 104 | foreach ($comparator->droppedColumns() as $column) { |
|
216 | 16 | $this->render( |
|
217 | $source, |
||
218 | ' ->addColumn(%s, %s, %s)', |
||
219 | 16 | $column->getName(), |
|
220 | 16 | $column->getDeclaredType() ?? $column->getAbstractType(), |
|
221 | $column |
||
222 | ); |
||
223 | } |
||
224 | |||
225 | 104 | foreach ($comparator->alteredColumns() as $pair) { |
|
226 | 48 | $this->alterColumn( |
|
227 | $source, |
||
228 | 48 | $pair[self::ORIGINAL_STATE], |
|
229 | 48 | $pair[self::NEW_STATE] |
|
230 | ); |
||
231 | } |
||
232 | |||
233 | 104 | foreach ($comparator->addedColumns() as $column) { |
|
234 | 16 | $this->render( |
|
235 | $source, |
||
236 | ' ->dropColumn(%s)', |
||
237 | 16 | $column->getName() |
|
238 | ); |
||
239 | } |
||
240 | } |
||
241 | |||
242 | 104 | private function revertIndexes(Source $source, Comparator $comparator): void |
|
243 | { |
||
244 | 104 | foreach ($comparator->droppedIndexes() as $index) { |
|
245 | 8 | $this->render( |
|
246 | $source, |
||
247 | ' ->addIndex(%s, %s)', |
||
248 | 8 | $index->getColumns(), |
|
249 | $index |
||
250 | ); |
||
251 | } |
||
252 | |||
253 | 104 | foreach ($comparator->alteredIndexes() as $pair) { |
|
254 | /** @var AbstractIndex $index */ |
||
255 | 16 | $index = $pair[self::ORIGINAL_STATE]; |
|
256 | 16 | $this->render( |
|
257 | $source, |
||
258 | ' ->alterIndex(%s, %s)', |
||
259 | 16 | $index->getColumns(), |
|
260 | $index |
||
261 | ); |
||
262 | } |
||
263 | |||
264 | 104 | foreach ($comparator->addedIndexes() as $index) { |
|
265 | 16 | $this->render( |
|
266 | $source, |
||
267 | ' ->dropIndex(%s)', |
||
268 | 16 | $index->getColumns() |
|
269 | ); |
||
270 | } |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * @param string $prefix Database isolation prefix. |
||
275 | */ |
||
276 | 104 | private function revertForeignKeys(Source $source, Comparator $comparator, string $prefix = ''): void |
|
277 | { |
||
278 | 104 | foreach ($comparator->droppedForeignKeys() as $key) { |
|
279 | 8 | $this->render( |
|
280 | $source, |
||
281 | ' ->addForeignKey(%s, %s, %s, %s)', |
||
282 | 8 | $key->getColumns(), |
|
283 | 8 | substr($key->getForeignTable(), strlen($prefix)), |
|
284 | 8 | $key->getForeignKeys(), |
|
285 | $key |
||
286 | ); |
||
287 | } |
||
288 | |||
289 | 104 | foreach ($comparator->alteredForeignKeys() as $pair) { |
|
290 | /** @var AbstractForeignKey $key */ |
||
291 | 8 | $key = $pair[self::ORIGINAL_STATE]; |
|
292 | 8 | $this->render( |
|
293 | $source, |
||
294 | ' ->alterForeignKey(%s, %s, %s, %s)', |
||
295 | 8 | $key->getColumns(), |
|
296 | 8 | substr($key->getForeignTable(), strlen($prefix)), |
|
297 | 8 | $key->getForeignKeys(), |
|
298 | $key |
||
299 | ); |
||
300 | } |
||
301 | |||
302 | 104 | foreach ($comparator->addedForeignKeys() as $key) { |
|
303 | 8 | $this->render($source, ' ->dropForeignKey(%s)', $key->getColumns()); |
|
304 | } |
||
305 | } |
||
306 | |||
307 | 48 | protected function alterColumn( |
|
308 | Source $source, |
||
309 | AbstractColumn $column, |
||
310 | AbstractColumn $original |
||
311 | ): void { |
||
312 | 48 | if ($column->getName() !== $original->getName()) { |
|
313 | 16 | $name = $original->getName(); |
|
314 | } else { |
||
315 | 32 | $name = $column->getName(); |
|
316 | } |
||
317 | |||
318 | 48 | $this->render( |
|
319 | $source, |
||
320 | ' ->alterColumn(%s, %s, %s)', |
||
321 | $name, |
||
322 | 48 | $column->getDeclaredType() ?? $column->getAbstractType(), |
|
323 | $column |
||
324 | ); |
||
325 | |||
326 | 48 | if ($column->getName() !== $original->getName()) { |
|
327 | 16 | $this->render( |
|
328 | $source, |
||
329 | ' ->renameColumn(%s, %s)', |
||
330 | $name, |
||
331 | 16 | $column->getName() |
|
332 | ); |
||
333 | } |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * Render values and options into source. |
||
338 | * |
||
339 | * @param array ...$values |
||
340 | */ |
||
341 | 144 | protected function render(Source $source, string $format, ...$values): void |
|
342 | { |
||
343 | 144 | $serializer = $this->getSerializer(); |
|
344 | |||
345 | 144 | $rendered = []; |
|
346 | 144 | foreach ($values as $value) { |
|
347 | 144 | if ($value instanceof AbstractTable) { |
|
348 | 144 | $rendered[] = $serializer->serialize( |
|
349 | 144 | substr($value->getName(), strlen($value->getPrefix())) |
|
350 | ); |
||
351 | 144 | continue; |
|
352 | } |
||
353 | |||
354 | 144 | if ($value instanceof AbstractColumn) { |
|
355 | 144 | $rendered[] = $this->columnOptions($serializer, $value); |
|
356 | 144 | continue; |
|
357 | } |
||
358 | |||
359 | 144 | if ($value instanceof AbstractIndex) { |
|
360 | 104 | $rendered[] = $this->indexOptions($serializer, $value); |
|
361 | 104 | continue; |
|
362 | } |
||
363 | |||
364 | 144 | if ($value instanceof AbstractForeignKey) { |
|
365 | 40 | $rendered[] = $this->foreignKeyOptions($serializer, $value); |
|
366 | 40 | continue; |
|
367 | } |
||
368 | |||
369 | // numeric array |
||
370 | 144 | if (is_array($value) && count($value) > 0 && is_numeric(array_keys($value)[0])) { |
|
371 | 136 | $rendered[] = '["' . implode('", "', $value) . '"]'; |
|
372 | 136 | continue; |
|
373 | } |
||
374 | |||
375 | 144 | $rendered[] = $serializer->serialize($value); |
|
376 | } |
||
377 | |||
378 | 144 | $lines = sprintf($format, ...$rendered); |
|
379 | 144 | foreach (explode("\n", $lines) as $line) { |
|
380 | 144 | $source->addLine($line); |
|
381 | } |
||
382 | } |
||
383 | |||
384 | 144 | private function columnOptions(Serializer $serializer, AbstractColumn $column): string |
|
385 | { |
||
386 | 144 | $options = [ |
|
387 | 144 | 'nullable' => $column->isNullable(), |
|
388 | 144 | 'default' => $column->getDefaultValue(), |
|
389 | ]; |
||
390 | |||
391 | 144 | if ($column->getAbstractType() === 'enum') { |
|
392 | 8 | $options['values'] = $column->getEnumValues(); |
|
393 | } |
||
394 | |||
395 | 144 | if ($column->getAbstractType() === 'string') { |
|
396 | 6 | $options['size'] = $column->getSize(); |
|
397 | } |
||
398 | |||
399 | 144 | if ($column->getAbstractType() === 'decimal') { |
|
400 | 8 | $options['scale'] = $column->getScale(); |
|
401 | 8 | $options['precision'] = $column->getPrecision(); |
|
402 | } |
||
403 | |||
404 | 144 | $default = $options['default']; |
|
405 | 144 | if ($column::DATETIME_NOW === ($default instanceof \Stringable ? (string)$default : $default)) { |
|
406 | 8 | $options['default'] = AbstractColumn::DATETIME_NOW; |
|
407 | } |
||
408 | |||
409 | 144 | return $this->mountIndents($serializer->serialize($options)); |
|
410 | } |
||
411 | |||
412 | 104 | private function indexOptions(Serializer $serializer, AbstractIndex $index): string |
|
413 | { |
||
414 | 104 | return $this->mountIndents( |
|
415 | 104 | $serializer->serialize( |
|
416 | [ |
||
417 | 104 | 'name' => $index->getName(), |
|
418 | 104 | 'unique' => $index->isUnique(), |
|
419 | ] |
||
420 | ) |
||
421 | ); |
||
422 | } |
||
423 | |||
424 | 40 | private function foreignKeyOptions( |
|
425 | Serializer $serializer, |
||
426 | AbstractForeignKey $reference |
||
427 | ): string { |
||
428 | 40 | return $this->mountIndents( |
|
429 | 40 | $serializer->serialize( |
|
430 | [ |
||
431 | 40 | 'name' => $reference->getName(), |
|
432 | 40 | 'delete' => $reference->getDeleteRule(), |
|
433 | 40 | 'update' => $reference->getUpdateRule(), |
|
434 | ] |
||
435 | ) |
||
436 | ); |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * Mount indents for column and index options. |
||
441 | * |
||
442 | * @param $serialized |
||
443 | */ |
||
444 | 144 | private function mountIndents(string $serialized): string |
|
445 | { |
||
446 | 144 | $lines = explode("\n", $serialized); |
|
447 | 144 | foreach ($lines as &$line) { |
|
448 | 144 | $line = ' ' . $line; |
|
449 | 144 | unset($line); |
|
450 | } |
||
451 | |||
452 | 144 | return ltrim(implode("\n", $lines)); |
|
453 | } |
||
454 | } |
||
455 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths