Passed
Push — master ( 674b34...f82c08 )
by Guillaume
02:11
created

MysqlDatabaseTable   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 45
dl 0
loc 291
c 0
b 0
f 0
rs 8.3673

19 Methods

Rating   Name   Duplication   Size   Complexity  
A formatCreateStatement() 0 12 4
A addIndex() 0 3 1
A addPrimary() 0 3 1
A getIndexes() 0 7 2
A getCollate() 0 3 1
B toArray() 0 32 5
A getTable() 0 3 1
A getIndex() 0 9 2
A formatStatements() 0 10 3
A setCollate() 0 3 1
A setDatabase() 0 3 1
A addColumn() 0 4 1
A addIndexType() 0 10 4
A addUnique() 0 3 1
A __construct() 0 7 2
A removeColumn() 0 4 1
A getColumns() 0 8 2
A alterStatement() 0 17 4
C createStatement() 0 33 8

How to fix   Complexity   

Complex Class

Complex classes like MysqlDatabaseTable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MysqlDatabaseTable, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Starkerxp\DatabaseChecker\Structure;
4
5
6
//@todo Manage data sync by option.
7
use Starkerxp\DatabaseChecker\Exception\DatabaseHasNotDefinedException;
8
use Starkerxp\DatabaseChecker\Exception\TableHasNotColumnException;
9
use Starkerxp\DatabaseChecker\Exception\TablenameHasNotDefinedException;
10
use Starkerxp\DatabaseChecker\LoggerTrait;
11
12
class MysqlDatabaseTable implements DatabaseInterface
13
{
14
15
    use LoggerTrait;
16
17
    /**
18
     * @var string
19
     */
20
    private $database;
21
22
    /**
23
     * @var string
24
     */
25
    private $table;
26
27
    /**
28
     * @var MysqlDatabaseColumn[]
29
     */
30
    private $columns = [];
31
32
    /**
33
     * @var MysqlDatabaseIndex[]
34
     */
35
    private $indexes = [];
36
37
    /**
38
     * @var string
39
     */
40
    private $collate;
41
42
    /**
43
     * DatabaseTableStructure constructor.
44
     *
45
     * @param $table
46
     *
47
     * @throws TablenameHasNotDefinedException
48
     */
49
    public function __construct($table)
50
    {
51
        if (empty($table)) {
52
            $this->critical('You need to define name of your table');
53
            throw new TablenameHasNotDefinedException('');
54
        }
55
        $this->table = $table;
56
    }
57
58
    public function addColumn(MysqlDatabaseColumn $column)
59
    {
60
        $column->setTable($this->getTable());
61
        $this->columns[$column->getName()] = $column;
62
    }
63
64
    /**
65
     * @return mixed
66
     */
67
    public function getTable()
68
    {
69
        return $this->table;
70
    }
71
72
    public function removeColumn($columnName)
73
    {
74
75
        unset($this->columns[$columnName]);
76
    }
77
78
    public function addIndex(array $columns, $indexName = '')
79
    {
80
        $this->addIndexType($indexName, 0, $columns);
81
    }
82
83
    /**
84
     * @param       $indexName
85
     * @param       $unique
86
     * @param array $columns
87
     */
88
    protected function addIndexType($indexName, $unique, array $columns)
89
    {
90
        if (empty($indexName)) {
91
            $indexName = ($unique ? 'UNI_' : 'IDX_') . md5(implode(',', $columns));
92
        }
93
        try {
94
            $index = new MysqlDatabaseIndex($indexName, $columns, $unique);
95
            $index->setTable($this->getTable());
96
            $this->indexes[$indexName] = $index;
97
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
98
99
        }
100
    }
101
102
    public function addPrimary(array $columnName)
103
    {
104
        $this->addIndexType('PRIMARY', 1, $columnName);
105
    }
106
107
    public function addUnique(array $columnName, $indexName = '')
108
    {
109
        $this->addIndexType($indexName, 1, $columnName);
110
    }
111
112
    public function toArray()
113
    {
114
        $export = [];
115
        $export['columns'] = [];
116
        $columns = $this->getColumns();
117
        foreach ($columns as $column) {
118
            $arrayColumn = $column->toArray();
119
            unset($arrayColumn['table']);
120
            $export['columns'][$column->getName()] = $arrayColumn;
121
        }
122
123
        $export['indexes'] = [];
124
        $export['uniques'] = [];
125
        $indexes = $this->getIndexes();
126
        foreach ($indexes as $index) {
127
            $arrayIndex = $index->toArray();
128
            if ($index->isPrimary()) {
129
                $export['primary'] = $index->getColumns();
130
                continue;
131
            }
132
            if ($index->isUnique()) {
133
                unset($arrayIndex['table'], $arrayIndex['unique']);
134
                $export['uniques'][] = $arrayIndex;
135
                continue;
136
            }
137
            unset($arrayIndex['table'], $arrayIndex['unique']);
138
            $export['indexes'][] = $arrayIndex;
139
        }
140
        $export['collate'] = $this->getCollate();
141
        $export = array_filter($export);
142
143
        return [$this->getTable() => $export];
144
    }
145
146
    /**
147
     * @return MysqlDatabaseColumn[]
148
     *
149
     * @throws TableHasNotColumnException
150
     */
151
    public function getColumns()
152
    {
153
        if (!count($this->columns)) {
154
            $this->critical('You need to define columns for this table.', ['table' => $this->getTable()]);
155
            throw new TableHasNotColumnException('');
156
        }
157
158
        return $this->columns;
159
    }
160
161
    public function getIndexes()
162
    {
163
        if (empty($this->indexes)) {
164
            $this->error("You don't have any index. Are you sure ?");
165
        }
166
167
        return $this->indexes;
168
    }
169
170
    /**
171
     * @return string
172
     */
173
    public function getCollate()
174
    {
175
        return $this->collate;
176
    }
177
178
    /**
179
     * @param string $collate
180
     */
181
    public function setCollate($collate)
182
    {
183
        $this->collate = $collate;
184
    }
185
186
    /**
187
     * @return array
188
     *
189
     * @throws TableHasNotColumnException
190
     */
191
    public function createStatement()
192
    {
193
        $modifications = [];
194
        $modifications[] = [sprintf('CREATE TABLE IF NOT EXISTS `%s`', $this->getTable())];
195
        $columns = $this->getColumns();
196
        foreach ($columns as $column) {
197
            try {
198
                if ($this->getCollate() == '') {
199
                    $column->setCollate('');
200
                }
201
                $modifications[] = $column->createStatement();
202
            } catch (TablenameHasNotDefinedException $e) {
203
                continue;
204
            }
205
        }
206
        $indexes = $this->getIndexes();
207
        foreach ($indexes as $index) {
208
            try {
209
                if (!$this->getIndex($index->getName())) {
210
                    continue;
211
                }
212
                $modifications[] = $index->createStatement();
213
            } catch (\Exception $e) {
214
                $this->critical('Unexpected error are throw.', ['table' => $this->getTable(), 'index' => $index->getName()]);
215
                continue;
216
            }
217
        }
218
219
        if (!$modifications = $this->formatStatements($modifications)) {
220
            return [];
221
        }
222
223
        return $this->formatCreateStatement($modifications);
224
225
    }
226
227
    /**
228
     * @param $indexName
229
     *
230
     * @return MysqlDatabaseIndex
231
     *
232
     * @throws \RuntimeException
233
     */
234
    public function getIndex($indexName)
235
    {
236
237
        if (empty($this->indexes[$indexName])) {
238
            $this->critical('You attempt to get undefined index name.', ['index' => $indexName]);
239
            throw new \RuntimeException('');
240
        }
241
242
        return $this->indexes[$indexName];
243
    }
244
245
    /**
246
     * @param array $modificationsBetweenTable
247
     *
248
     * @return array
249
     */
250
    private function formatStatements(array $modificationsBetweenTable)
251
    {
252
        $statements = [];
253
        foreach ($modificationsBetweenTable as $modifications) {
254
            foreach ((array)$modifications as $modification) {
255
                $statements[] = $modification;
256
            }
257
        }
258
259
        return array_filter(array_unique($statements));
260
    }
261
262
    private function formatCreateStatement(array $modifications)
263
    {
264
        if (!$finalStatement = array_shift($modifications)) {
265
            return [];
266
        }
267
        $tmp = [];
268
        foreach ($modifications as $modification) {
269
            $tmp[] = trim(str_replace(['ALTER TABLE `' . $this->getTable() . '` ADD COLUMN', 'ALTER TABLE `' . $this->getTable() . '` ADD ', ';',], '', $modification));
270
        }
271
        $collate = $this->getCollate() == '' ? '' : sprintf("COLLATE='%s'", $this->getCollate());
272
273
        return [$finalStatement . '(' . implode(',', $tmp) . ')' . $collate . ';'];
274
    }
275
276
    /**
277
     *
278
     * @throws \RuntimeException
279
     * @throws DatabaseHasNotDefinedException
280
     */
281
    public function alterStatement()
282
    {
283
        if (empty($this->database)) {
284
            throw new DatabaseHasNotDefinedException('');
285
        }
286
        $collateTmp = $this->getCollate();
287
        $collate = $collateTmp == '' ? '' : sprintf('CONVERT TO CHARACTER SET %s COLLATE %s', explode('_', $collateTmp)[0], $collateTmp);
288
        if ($collate == '') {
289
            throw new \RuntimeException('Not implemented');
290
        }
291
292
        $modifications = [
293
            sprintf('ALTER DATABASE %s CHARACTER SET %s COLLATE %s;', $this->database, explode('_', $collateTmp)[0], $collateTmp),
294
            sprintf('ALTER TABLE `%s` %s;', $this->getTable(), $collate),
295
        ];
296
297
        return $modifications;
298
    }
299
300
    public function setDatabase($database)
301
    {
302
        $this->database = $database;
303
    }
304
305
}
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...
306