Failed Conditions
Push — master ( ea4232...3b6e69 )
by Grégoire
17:30 queued 17:24
created

SchemaDiff::getNewTablesSortedByDependencies()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 23
ccs 0
cts 0
cp 0
rs 9.5555
cc 5
nc 8
nop 0
crap 30
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Schema;
6
7
use Doctrine\DBAL\Internal\DependencyOrderCalculator;
8
use Doctrine\DBAL\Platforms\AbstractPlatform;
9
use function array_merge;
10
11
/**
12
 * Schema Diff.
13
 */
14
class SchemaDiff
15
{
16
    /** @var Schema|null */
17
    public $fromSchema;
18
19
    /**
20
     * All added namespaces.
21
     *
22
     * @var array<string, string>
23
     */
24
    public $newNamespaces = [];
25
26
    /**
27
     * All removed namespaces.
28
     *
29
     * @var array<string, string>
30
     */
31
    public $removedNamespaces = [];
32
33
    /**
34
     * All added tables.
35
     *
36
     * @var array<string, Table>
37
     */
38
    public $newTables = [];
39
40
    /**
41
     * All changed tables.
42
     *
43
     * @var array<string, TableDiff>
44
     */
45
    public $changedTables = [];
46
47
    /**
48
     * All removed tables.
49
     *
50
     * @var array<string, Table>
51
     */
52
    public $removedTables = [];
53
54
    /** @var array<int, Sequence> */
55
    public $newSequences = [];
56
57
    /** @var array<int, Sequence> */
58
    public $changedSequences = [];
59
60
    /** @var array<int, Sequence> */
61
    public $removedSequences = [];
62
63
    /** @var array<string|int, ForeignKeyConstraint> */
64
    public $orphanedForeignKeys = [];
65
66
    /**
67
     * Constructs an SchemaDiff object.
68
     *
69
     * @param array<string, Table>     $newTables
70
     * @param array<string, TableDiff> $changedTables
71
     * @param array<string, Table>     $removedTables
72 669
     */
73
    public function __construct(array $newTables = [], array $changedTables = [], array $removedTables = [], ?Schema $fromSchema = null)
74 669
    {
75 669
        $this->newTables     = $newTables;
76 669
        $this->changedTables = $changedTables;
77 669
        $this->removedTables = $removedTables;
78 669
        $this->fromSchema    = $fromSchema;
79
    }
80
81
    /**
82
     * The to save sql mode ensures that the following things don't happen:
83
     *
84
     * 1. Tables are deleted
85
     * 2. Sequences are deleted
86
     * 3. Foreign Keys which reference tables that would otherwise be deleted.
87
     *
88
     * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all.
89
     *
90
     * @return array<int, string>
91 22
     */
92
    public function toSaveSql(AbstractPlatform $platform) : array
93 22
    {
94
        return $this->_toSql($platform, true);
95
    }
96
97
    /**
98
     * @return array<int, string>
99 75
     */
100
    public function toSql(AbstractPlatform $platform) : array
101 75
    {
102
        return $this->_toSql($platform, false);
103
    }
104
105
    /**
106
     * @return array<int, string>
107 97
     */
108
    protected function _toSql(AbstractPlatform $platform, bool $saveMode = false) : array
109 97
    {
110
        $sql = [];
111 97
112 51
        if ($platform->supportsSchemas()) {
113 51
            foreach ($this->newNamespaces as $newNamespace) {
114
                $sql[] = $platform->getCreateSchemaSQL($newNamespace);
115
            }
116
        }
117 97
118 53
        if ($platform->supportsForeignKeyConstraints() && $saveMode === false) {
119 22
            foreach ($this->orphanedForeignKeys as $orphanedForeignKey) {
120
                $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTable());
121
            }
122
        }
123 97
124 51
        if ($platform->supportsSequences()) {
125 44
            foreach ($this->changedSequences as $sequence) {
126
                $sql[] = $platform->getAlterSequenceSQL($sequence);
127
            }
128 51
129 29
            if ($saveMode === false) {
130 22
                foreach ($this->removedSequences as $sequence) {
131
                    $sql[] = $platform->getDropSequenceSQL($sequence);
132
                }
133
            }
134 51
135 44
            foreach ($this->newSequences as $sequence) {
136
                $sql[] = $platform->getCreateSequenceSQL($sequence);
137
            }
138
        }
139 97
140 97
        $foreignKeySql = [];
141 66
        $createFlags   = AbstractPlatform::CREATE_INDEXES;
142 66
143 66
        if (! $platform->supportsCreateDropForeignKeyConstraints()) {
144
            $createFlags |= AbstractPlatform::CREATE_FOREIGNKEYS;
145
        }
146 66
147 22
        foreach ($this->getNewTablesSortedByDependencies() as $table) {
148
            $sql = array_merge($sql, $platform->getCreateTableSQL($table, $createFlags));
149
150 44
            if (! $platform->supportsCreateDropForeignKeyConstraints()) {
151 44
                continue;
152
            }
153
154
            foreach ($table->getForeignKeys() as $foreignKey) {
155 97
                $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table);
156
            }
157 97
        }
158 75
159 22
        $sql = array_merge($sql, $foreignKeySql);
160
161
        if ($saveMode === false) {
162
            foreach ($this->removedTables as $table) {
163 97
                $sql[] = $platform->getDropTableSQL($table);
164 68
            }
165
        }
166
167 97
        foreach ($this->changedTables as $tableDiff) {
168
            $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff));
169
        }
170
171
        return $sql;
172
    }
173
174
    /**
175
     * Sorts tables by dependencies so that they are created in the right order.
176
     *
177
     * This is necessary when one table depends on another while creating foreign key
178
     * constraints directly during CREATE TABLE.
179
     *
180
     * @return array<Table>
181
     */
182
    private function getNewTablesSortedByDependencies()
183
    {
184
        $calculator = new DependencyOrderCalculator();
185
        $newTables  = [];
186
187
        foreach ($this->newTables as $table) {
188
            $newTables[$table->getName()] = true;
189
            $calculator->addNode($table->getName(), $table);
190
        }
191
192
        foreach ($this->newTables as $table) {
193
            foreach ($table->getForeignKeys() as $foreignKey) {
194
                $foreignTableName = $foreignKey->getForeignTableName();
195
196
                if (! isset($newTables[$foreignTableName])) {
197
                    continue;
198
                }
199
200
                $calculator->addDependency($foreignTableName, $table->getName());
201
            }
202
        }
203
204
        return $calculator->sort();
205
    }
206
}
207