Passed
Push — master ( 415713...bcbace )
by Guillaume
02:07
created

MysqlDatabaseTable   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 43
dl 0
loc 263
rs 8.3157
c 0
b 0
f 0

18 Methods

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