MysqlDatabaseCheckerService::getTable()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
c 0
b 0
f 0
rs 10
cc 3
nc 3
nop 2
1
<?php
2
3
namespace Starkerxp\DatabaseChecker\Checker;
4
5
use Starkerxp\DatabaseChecker\Exception\ColumnNotExistException;
6
use Starkerxp\DatabaseChecker\Exception\IndexNotExistException;
7
use Starkerxp\DatabaseChecker\Exception\TableHasNotColumnException;
8
use Starkerxp\DatabaseChecker\Exception\TableNotExistException;
9
use Starkerxp\DatabaseChecker\LoggerTrait;
10
use Starkerxp\DatabaseChecker\Structure\DatabaseInterface;
11
use Starkerxp\DatabaseChecker\Structure\MysqlDatabase;
12
use Starkerxp\DatabaseChecker\Structure\MysqlDatabaseColumn;
13
use Starkerxp\DatabaseChecker\Structure\MysqlDatabaseIndex;
14
use Starkerxp\DatabaseChecker\Structure\MysqlDatabaseTable;
15
16
class MysqlDatabaseCheckerService
17
{
18
    use LoggerTrait;
19
20
    /**
21
     * @var boolean
22
     */
23
    private $checkCollate;
24
25
    /**
26
     * @var boolean
27
     */
28
    private $checkEngine;
29
30
    /**
31
     * @var boolean
32
     */
33
    private $dropStatement;
34
35
    /**
36
     * @param MysqlDatabase $database
37
     * @param MysqlDatabase $newDatabase
38
     * @return array
39
     * @throws TableHasNotColumnException
40
     * @throws \Starkerxp\DatabaseChecker\Exception\TablenameHasNotDefinedException
41
     */
42
    public function diff(MysqlDatabase $database, MysqlDatabase $newDatabase): array
43
    {
44
        $modificationsBetweenTable = [];
45
        $tables = $database->getTables();
46
        $newTables = $newDatabase->getTables();
47
48
        if ($this->checkCollate && $database->getCollate() != $newDatabase->getCollate()) {
49
            $database->setCollate($newDatabase->getCollate());
50
            $modificationsBetweenTable[] = $database->alterStatement();
51
        }
52
53
        // check Table
54
        foreach ($tables as $table) {
55
            try {
56
                $newTable = $this->getTable($table, $newTables);
57
                $modificationsBetweenTable[] = $this->checkTable($table, $newTable);
58
            } catch (TableNotExistException $e) {
59
                //@todo Drop statement.
60
                //@todo config for generate create or drop.
61
                $modificationsBetweenTable[] = $this->createStatement($table);
62
                continue;
63
            }
64
        }
65
66
        foreach ($newTables as $newTable) {
67
            try {
68
                $this->getTable($newTable, $tables);
69
            } catch (TableNotExistException $e) {
70
                $modificationsBetweenTable[] = $this->createStatement($newTable);
71
                continue;
72
            }
73
        }
74
75
        return $this->formatStatements($modificationsBetweenTable);
76
    }
77
78
    /**
79
     * @param MysqlDatabaseTable $table
80
     * @param MysqlDatabaseTable[] $newTables
81
     *
82
     * @return mixed
83
     * @throws TableNotExistException
84
     */
85
    private function getTable($table, array $newTables)
86
    {
87
        foreach ($newTables as $newTable) {
88
            if (strtolower($table->getTable()) == strtolower($newTable->getTable())) {
89
                return $newTable;
90
            }
91
        }
92
        throw new TableNotExistException('');
93
    }
94
95
    /**
96
     * @param MysqlDatabaseTable $table
97
     * @param MysqlDatabaseTable $newTable
98
     *
99
     * @return array
100
     *
101
     * @throws TableHasNotColumnException
102
     * @throws \Starkerxp\DatabaseChecker\Exception\TablenameHasNotDefinedException
103
     */
104
    private function checkTable(MysqlDatabaseTable $table, MysqlDatabaseTable $newTable): array
105
    {
106
        $this->prepareTable($table);
107
        $this->prepareTable($newTable);
108
        // Aucune différence
109
        if ($this->tableIsEquals($table, $newTable)) {
110
            return [];
111
        }
112
113
        $modificationsBetweenTable = $newTable->alterStatement();
114
        $columns = $table->getColumns();
115
        $newColumns = $newTable->getColumns();
116
117
        foreach ($columns as $column) {
118
            try {
119
                $newColumn = $this->getColumn($column, $newColumns);
120
                $modificationsBetweenTable[$newColumn->getName()] = $this->checkColumn($column, $newColumn);
121
            } catch (ColumnNotExistException $e) {
122
                if ($this->dropStatement) {
123
                    $modificationsBetweenTable[$column->getName()] = $column->deleteStatement();
124
                    continue;
125
                }
126
                $modificationsBetweenTable[$column->getName()] = $this->createStatement($column);
127
                continue;
128
            } catch (\Exception $e) {
129
                continue;
130
            }
131
        }
132
        $columnNeedAlter = array_unique(array_keys(array_filter($modificationsBetweenTable)));
133
        $indexes = $table->getIndexes();
134
        $newIndexes = $newTable->getIndexes();
135
136
        $modificationsIndexBetweenTable = [];
137
        $modificationsIndexRemoveBetweenTable = [];
138
        foreach ($indexes as $index) {
139
            try {
140
                $newIndex = $this->getIndex($index, $newIndexes);
141
                $modificationsIndexBetweenTable[$newColumn->getName()] = $this->checkIndex($index, $newIndex);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $newColumn seems to be defined by a foreach iteration on line 117. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
142
            } catch (IndexNotExistException $e) {
143
                if ($this->dropStatement) {
144
                    $modificationsIndexRemoveBetweenTable[$index->getName()] = $index->deleteStatement();
145
                    continue;
146
                }
147
            } catch (\Exception $e) {
148
                continue;
149
            }
150
        }
151
        // Generate new Indexes.
152
        foreach ($newIndexes as $index) {
153
            try {
154
                $this->getIndex($index, $indexes);
155
            } catch (IndexNotExistException $e) {
156
                $modificationsIndexBetweenTable[$index->getName()] = $index->createStatement();
157
            } catch (\Exception $e) {
158
                continue;
159
            }
160
        }
161
162
        foreach ($newIndexes as $indexName => $index) {
163
            foreach ($columnNeedAlter as $colonne) {
164
                if (!in_array($colonne, $index->getColumns(), false)) {
165
                    continue;
166
                }
167
                $modificationsIndexRemoveBetweenTable[] = $index->deleteStatement();
168
                $modificationsIndexBetweenTable[] = $index->createStatement();
169
            }
170
        }
171
172
        $modificationsIndexBetweenTable = $this->formatStatements(array_filter($modificationsIndexBetweenTable));
173
        $modificationsIndexRemoveBetweenTable = $this->formatStatements(array_filter($modificationsIndexRemoveBetweenTable));
174
175
        $modificationsBetweenTable = $this->formatStatements($modificationsBetweenTable);
176
177
        $result = array_merge($modificationsIndexRemoveBetweenTable, $modificationsBetweenTable, $modificationsIndexBetweenTable);
178
179
        return $result;
180
    }
181
182
    private function prepareTable(MysqlDatabaseTable $table): void
183
    {
184
        if (!$this->checkCollate) {
185
            $this->disabledCollate($table);
186
        }
187
        if (!$this->checkEngine) {
188
            $table->setEngine('');
189
        }
190
    }
191
192
    /**
193
     * @param MysqlDatabaseTable $table
194
     * @throws TableHasNotColumnException
195
     */
196
    private function disabledCollate(MysqlDatabaseTable $table): void
197
    {
198
        $table->setCollate('');
199
        $columns = $table->getColumns();
200
        foreach ($columns as $column) {
201
            $column->setCollate('');
202
        }
203
    }
204
205
    private function tableIsEquals(MysqlDatabaseTable $table, MysqlDatabaseTable $newTable): bool
206
    {
207
        // Table is equals no need more check
208
        if ($table == $newTable) {
209
            return true;
210
        }
211
212
        return strtolower(json_encode($table->toArray())) == strtolower(json_encode($newTable->toArray()));
213
    }
214
215
    /**
216
     * @param MysqlDatabaseColumn $column
217
     * @param MysqlDatabaseColumn[] $newColumns
218
     *
219
     * @return mixed
220
     *
221
     * @throws ColumnNotExistException
222
     */
223
    private function getColumn(MysqlDatabaseColumn $column, array $newColumns)
224
    {
225
        foreach ($newColumns as $newColumn) {
226
            if (strtolower($column->getName()) == strtolower($newColumn->getName())) {
227
                return $newColumn;
228
            }
229
        }
230
        throw new ColumnNotExistException('');
231
    }
232
233
    /**
234
     * @param MysqlDatabaseColumn $column
235
     * @param MysqlDatabaseColumn $newColumn
236
     *
237
     * @return array
238
     *
239
     * @throws \Starkerxp\DatabaseChecker\Exception\TablenameHasNotDefinedException
240
     */
241
    private function checkColumn(MysqlDatabaseColumn $column, MysqlDatabaseColumn $newColumn): array
242
    {
243
        if ($this->columnIsEquals($column, $newColumn)) {
244
            return [];
245
        }
246
        try {
247
            $statements = $newColumn->alterStatement();
248
        } catch (\RuntimeException $e) {
249
            return [];
250
        }
251
252
        return $statements;
253
    }
254
255
    private function columnIsEquals(MysqlDatabaseColumn $column, MysqlDatabaseColumn $newColumn): bool
256
    {
257
        // Column is equals no need more check
258
        if ($column == $newColumn) {
259
            return true;
260
        }
261
262
        return strtolower(json_encode($column->toArray())) == strtolower(json_encode($newColumn->toArray()));
263
    }
264
265
    private function getIndex(MysqlDatabaseIndex $index, array $newIndexes)
266
    {
267
        foreach ($newIndexes as $newIndex) {
268
            if (strtolower($index->getName()) == strtolower($newIndex->getName())) {
269
                return $newIndex;
270
            }
271
        }
272
        throw new IndexNotExistException('');
273
    }
274
275
    private function checkIndex(MysqlDatabaseIndex $index, MysqlDatabaseIndex $newIndex): array
276
    {
277
        if ($this->indexIsEquals($index, $newIndex)) {
278
            return [];
279
        }
280
        try {
281
            $statements = $newIndex->alterStatement();
282
        } catch (\RuntimeException $e) {
283
            return [];
284
        }
285
286
        return $statements;
287
    }
288
289
    private function indexIsEquals(MysqlDatabaseIndex $index, MysqlDatabaseIndex $newIndex): bool
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

289
    private function indexIsEquals(/** @scrutinizer ignore-unused */ MysqlDatabaseIndex $index, MysqlDatabaseIndex $newIndex): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $newIndex is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

289
    private function indexIsEquals(MysqlDatabaseIndex $index, /** @scrutinizer ignore-unused */ MysqlDatabaseIndex $newIndex): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
290
    {
291
        // Column is equals no need more check
292
        if ($column == $newColumn) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $newColumn seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $column seems to be never defined.
Loading history...
293
            return true;
294
        }
295
296
        return strtolower(json_encode($column->toArray())) == strtolower(json_encode($newColumn->toArray()));
297
    }
298
299
    /**
300
     * @param  $databaseInterface
301
     *
302
     * @return array
303
     */
304
    protected function createStatement(DatabaseInterface $databaseInterface): ?array
305
    {
306
        try {
307
            return $databaseInterface->createStatement();
308
        } catch (TableHasNotColumnException $e) {
309
            return [];
310
        }
311
    }
312
313
    /**
314
     * @param array $modificationsBetweenTable
315
     *
316
     * @return array
317
     */
318
    private function formatStatements(array $modificationsBetweenTable): array
319
    {
320
        $statements = [];
321
        foreach ($modificationsBetweenTable as $modifications) {
322
            foreach ((array) $modifications as $modification) {
323
                $statements[] = $modification;
324
            }
325
        }
326
327
        return array_filter(array_unique($statements));
328
    }
329
330
    public function enableCheckCollate(): void
331
    {
332
        $this->checkCollate = true;
333
    }
334
335
    public function enableCheckEngine(): void
336
    {
337
        $this->checkEngine = true;
338
    }
339
340
    public function enableDropStatement(): void
341
    {
342
        $this->dropStatement = true;
343
    }
344
345
}
346