Passed
Branch 2.0 (27b8db)
by Anton
05:03
created

ShowChanges::describeChanges()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 27
rs 9.7333
c 0
b 0
f 0
cc 4
nc 5
nop 1
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
declare(strict_types=1);
9
10
namespace Spiral\Command\Cycle\Generator;
11
12
use Cycle\Schema\GeneratorInterface;
13
use Cycle\Schema\Registry;
14
use Spiral\Database\Schema\AbstractTable;
15
use Spiral\Database\Schema\Comparator;
16
use Symfony\Component\Console\Output\OutputInterface;
17
18
final class ShowChanges implements GeneratorInterface
19
{
20
    /** @var OutputInterface */
21
    private $output;
22
23
    /** @var array */
24
    private $changes = [];
25
26
    /**
27
     * @param OutputInterface $output
28
     */
29
    public function __construct(OutputInterface $output)
30
    {
31
        $this->output = $output;
32
    }
33
34
    /**
35
     * @param Registry $registry
36
     * @return Registry
37
     */
38
    public function run(Registry $registry): Registry
39
    {
40
        $this->output->writeln("<info>Detecting schema changes:</info>");
41
42
        $this->changes = [];
43
        foreach ($registry->getIterator() as $e) {
44
            if ($registry->hasTable($e)) {
45
                $table = $registry->getTableSchema($e);
46
47
                if ($table->getComparator()->hasChanges()) {
48
                    $this->changes[] = [
49
                        'database' => $registry->getDatabase($e),
50
                        'table'    => $registry->getTable($e),
51
                        'schema'   => $table,
52
                    ];
53
                }
54
            }
55
        }
56
57
        if ($this->changes === []) {
58
            $this->output->writeln("<fg=yellow>no database changes has been detected</fg=yellow>");
59
60
            return $registry;
61
        }
62
63
        foreach ($this->changes as $change) {
64
            $this->output->write(sprintf("• <fg=cyan>%s.%s</fg=cyan>", $change['database'], $change['table']));
65
            $this->describeChanges($change['schema']);
66
        }
67
68
        return $registry;
69
    }
70
71
    /**
72
     * @param AbstractTable $table
73
     */
74
    protected function describeChanges(AbstractTable $table)
75
    {
76
        if (!$this->output->isVerbose()) {
77
            $this->output->writeln(sprintf(
78
                ": <fg=green>%s</fg=green> change(s) detected",
79
                $this->numChanges($table)
80
            ));
81
82
            return;
83
        } else {
84
            $this->output->write("\n");
85
        }
86
87
        if (!$table->exists()) {
88
            $this->output->writeln("    - create table");
89
        }
90
91
        if ($table->getStatus() === AbstractTable::STATUS_DECLARED_DROPPED) {
92
            $this->output->writeln("    - drop table");
93
            return;
94
        }
95
96
        $cmp = $table->getComparator();
97
98
        $this->describeColumns($cmp);
99
        $this->describeIndexes($cmp);
100
        $this->describeFKs($cmp);
101
    }
102
103
    /**
104
     * @param Comparator $cmp
105
     */
106
    protected function describeColumns(Comparator $cmp)
107
    {
108
        foreach ($cmp->addedColumns() as $column) {
109
            $this->output->writeln("    - add column <fg=yellow>{$column->getName()}</fg=yellow>");
110
        }
111
112
        foreach ($cmp->droppedColumns() as $column) {
113
            $this->output->writeln("    - drop column <fg=yellow>{$column->getName()}</fg=yellow>");
114
        }
115
116
        foreach ($cmp->alteredColumns() as $column) {
117
            $column = $column[0];
118
            $this->output->writeln("    - alter column <fg=yellow>{$column->getName()}</fg=yellow>");
119
        }
120
    }
121
122
    /**
123
     * @param Comparator $cmp
124
     */
125
    protected function describeIndexes(Comparator $cmp)
126
    {
127
        foreach ($cmp->addedIndexes() as $index) {
128
            $index = join(', ', $index->getColumns());
129
            $this->output->writeln("    - add index on <fg=yellow>[{$index}]</fg=yellow>");
130
        }
131
132
        foreach ($cmp->droppedIndexes() as $index) {
133
            $this->output->writeln("    - drop index on <fg=yellow>[{$index}]</fg=yellow>");
134
        }
135
136
        foreach ($cmp->alteredIndexes() as $index) {
137
            $index = $index[0];
138
            $this->output->writeln("    - alter index on <fg=yellow>[{$index}]</fg=yellow>");
139
        }
140
    }
141
142
    /**
143
     * @param Comparator $cmp
144
     */
145
    protected function describeFKs(Comparator $cmp)
146
    {
147
        foreach ($cmp->addedForeignKeys() as $fk) {
148
            $this->output->writeln("    - add foreign key on <fg=yellow>{$fk->getColumn()}</fg=yellow>");
149
        }
150
151
        foreach ($cmp->droppedForeignKeys() as $fk) {
152
            $this->output->writeln("    - drop foreign key <fg=yellow>{$fk->getColumn()}</fg=yellow>");
153
        }
154
155
        foreach ($cmp->alteredForeignKeys() as $fk) {
156
            $fk = $fk[0];
157
            $this->output->writeln("    - alter foreign key <fg=yellow>{$fk->getColumn()}</fg=yellow>");
158
        }
159
    }
160
161
    /**
162
     * @param AbstractTable $table
163
     * @return int
164
     */
165
    protected function numChanges(AbstractTable $table): int
166
    {
167
        $cmp = $table->getComparator();
168
169
        return count($cmp->addedColumns())
170
            + count($cmp->droppedColumns())
171
            + count($cmp->alteredColumns())
172
            + count($cmp->addedIndexes())
173
            + count($cmp->droppedIndexes())
174
            + count($cmp->alteredIndexes())
175
            + count($cmp->addedForeignKeys())
176
            + count($cmp->droppedForeignKeys())
177
            + count($cmp->alteredForeignKeys());
178
    }
179
180
    /**
181
     * @return bool
182
     */
183
    public function hasChanges(): bool
184
    {
185
        return $this->changes !== [];
186
    }
187
}