Completed
Branch feature/pre-split (67216b)
by Anton
03:22
created

Atomizer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 130
rs 10
c 0
b 0
f 0
wmc 16
lcom 1
cbo 6

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A addTable() 0 6 1
A getTables() 0 4 1
A declareChanges() 0 17 4
A revertChanges() 0 17 4
A sortedTables() 0 18 3
A declareBlock() 0 6 2
1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Migrations;
8
9
use Spiral\Core\Component;
10
use Spiral\Database\Schemas\Prototypes\AbstractTable;
11
use Spiral\Migrations\Atomizer\RendererInterface;
12
use Spiral\Reactor\Body\Source;
13
use Spiral\Support\DFSSorter;
14
15
/**
16
 * Atomizer provides ability to convert given AbstractTables and their changes into set of
17
 * migration commands.
18
 */
19
class Atomizer extends Component
20
{
21
    /**
22
     * Render changes into source.
23
     *
24
     * @var RendererInterface
25
     */
26
    private $renderer;
27
28
    /**
29
     * @var AbstractTable[]
30
     */
31
    protected $tables = [];
32
33
    /**
34
     * @param RendererInterface $renderer
35
     */
36
    public function __construct(RendererInterface $renderer)
37
    {
38
        $this->renderer = $renderer;
39
    }
40
41
    /**
42
     * Add new table into atomizer.
43
     *
44
     * @param AbstractTable $table
45
     *
46
     * @return Atomizer
47
     */
48
    public function addTable(AbstractTable $table): self
49
    {
50
        $this->tables[] = $table;
51
52
        return $this;
53
    }
54
55
    /**
56
     * Get all atomizer tables.
57
     *
58
     * @return AbstractTable[]
59
     */
60
    public function getTables(): array
61
    {
62
        return $this->tables;
63
    }
64
65
    /**
66
     * Generate set of commands needed to describe migration (up command).
67
     *
68
     * @param Source $source
69
     */
70
    public function declareChanges(Source $source)
71
    {
72
        foreach ($this->sortedTables() as $table) {
73
            if (!$table->getComparator()->hasChanges()) {
74
                continue;
75
            }
76
77
            //New operations block
78
            $this->declareBlock($source);
79
80
            if (!$table->exists()) {
81
                $this->renderer->createTable($source, $table);
82
            } else {
83
                $this->renderer->updateTable($source, $table);
84
            }
85
        }
86
    }
87
88
    /**
89
     * Generate set of lines needed to rollback migration (down command).
90
     *
91
     * @param Source $source
92
     */
93
    public function revertChanges(Source $source)
94
    {
95
        foreach ($this->sortedTables(true) as $table) {
96
            if (!$table->getComparator()->hasChanges()) {
97
                continue;
98
            }
99
100
            //New operations block
101
            $this->declareBlock($source);
102
103
            if (!$table->exists()) {
104
                $this->renderer->dropTable($source, $table);
105
            } else {
106
                $this->renderer->revertTable($source, $table);
107
            }
108
        }
109
    }
110
111
    /**
112
     * Tables sorted in order of their dependecies.
113
     *
114
     * @param bool $reverse
115
     *
116
     * @return AbstractTable[]
117
     */
118
    protected function sortedTables($reverse = false)
119
    {
120
        /*
121
         * Tables has to be sorted using topological graph to execute operations in a valid order.
122
         */
123
        $sorter = new DFSSorter();
124
        foreach ($this->tables as $table) {
125
            $sorter->addItem($table->getName(), $table, $table->getDependencies());
126
        }
127
128
        $tables = $sorter->sort();
129
130
        if ($reverse) {
131
            return array_reverse($tables);
132
        }
133
134
        return $tables;
135
    }
136
137
    /**
138
     * Add spacing between commands, only if required.
139
     *
140
     * @param Source $source
141
     */
142
    private function declareBlock(Source $source)
143
    {
144
        if (!empty($source->getLines())) {
145
            $source->addLine("");
146
        }
147
    }
148
}