Completed
Push — master ( 3de301...5f0182 )
by Guillaume
02:25
created

MysqlDatabaseCheckerService::checkTable()   D

Complexity

Conditions 9
Paths 33

Size

Total Lines 41
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

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

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
268