MysqlDatabaseTable::addColumn()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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