Table   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 296
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 79
c 1
b 0
f 0
dl 0
loc 296
rs 9.92
wmc 31

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A setAction() 0 10 2
A modifyColumn() 0 10 2
A dropColumn() 0 6 2
A __destruct() 0 3 1
A addIndex() 0 9 2
A renameColumn() 0 6 2
A dropIndex() 0 6 2
A renameTo() 0 4 1
A __call() 0 8 2
A addColumn() 0 8 2
A checkColumnExists() 0 14 3
A after() 0 4 1
A getSql() 0 20 5
A save() 0 6 2
A columnKey() 0 3 1
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.0
13
 */
14
15
namespace Quantum\Libraries\Database\Schema;
16
17
use Quantum\Exceptions\DatabaseException;
18
use Quantum\Exceptions\MigrationException;
19
use Quantum\Libraries\Database\Database;
20
use Quantum\Exceptions\LangException;
21
22
/**
23
 * Class Table
24
 * @package Quantum\Libraries\Database
25
 *
26
 * @method self autoIncrement()
27
 * @method self primary()
28
 * @method self index(string $name = null)
29
 * @method self unique(string $name = null)
30
 * @method self fulltext(string $name = null)
31
 * @method self spatial(string $name = null)
32
 * @method self nullable(bool $indeed = true)
33
 * @method self default($value, bool $quoted = true)
34
 * @method self defaultQuoted()
35
 * @method self attribute(?string $value)
36
 * @method self comment(?string $value)
37
 */
38
class Table
39
{
40
41
    use TableBuilder;
42
43
    /**
44
     * Action create
45
     */
46
    const CREATE = 1;
47
48
    /**
49
     * Action alter
50
     */
51
    const ALTER = 2;
52
53
    /**
54
     * Action drop
55
     */
56
    const DROP = 3;
57
58
    /**
59
     * Action rename
60
     */
61
    const RENAME = 4;
62
63
    /**
64
     * @var string
65
     */
66
    private $name;
67
68
    /**
69
     * @var string
70
     */
71
    private $newName;
72
73
    /**
74
     * @var int
75
     */
76
    private $action = null;
77
78
    /**
79
     * @var array
80
     */
81
    private $columns = [];
82
83
    /**
84
     * @var array
85
     */
86
    private $indexKeys = [];
87
88
    /**
89
     * @var array
90
     */
91
    private $droppedIndexKeys = [];
92
93
    /**
94
     * Table constructor.
95
     * @param string $name
96
     */
97
    public function __construct(string $name)
98
    {
99
        $this->name = $name;
100
    }
101
102
    /**
103
     * Table destructor
104
     * Saves the data before object goes out of scope
105
     */
106
    public function __destruct()
107
    {
108
        $this->save();
109
    }
110
111
    /**
112
     * Renames the table
113
     * @param string $newName
114
     * @return Table
115
     */
116
    public function renameTo(string $newName): Table
117
    {
118
        $this->newName = $newName;
119
        return $this;
120
    }
121
122
    /**
123
     * Sets an action on a table to be performed
124
     * @param int $action
125
     * @param array|null $data
126
     * @return Table
127
     */
128
    public function setAction(int $action, ?array $data = null): Table
129
    {
130
        $this->action = $action;
131
132
        if ($data) {
133
            $key = key($data);
134
            $this->$key = $data[$key];
135
        }
136
137
        return $this;
138
    }
139
140
    /**
141
     * Adds column to the table
142
     * @param string $name
143
     * @param string $type
144
     * @param mixed $constraint
145
     * @return Table
146
     */
147
    public function addColumn(string $name, string $type, $constraint = null): Table
148
    {
149
        $this->columns[] = [
150
            'column' => new Column($name, $type, $constraint),
151
            'action' => $this->action == self::ALTER ? Column::ADD : null
152
        ];
153
154
        return $this;
155
    }
156
157
    /**
158
     * Modifies the column
159
     * @param string $name
160
     * @param string $type
161
     * @param mixed $constraint
162
     * @return Table
163
     */
164
    public function modifyColumn(string $name, string $type, $constraint = null): Table
165
    {
166
        if ($this->action == self::ALTER) {
167
            $this->columns[] = [
168
                'column' => new Column($name, $type, $constraint),
169
                'action' => Column::MODIFY
170
            ];
171
        }
172
173
        return $this;
174
    }
175
176
    /**
177
     * Renames the column name
178
     * @param string $oldName
179
     * @param string $newName
180
     */
181
    public function renameColumn(string $oldName, string $newName)
182
    {
183
        if ($this->action == self::ALTER) {
184
            $this->columns[] = [
185
                'column' => (new Column($oldName))->renameTo($newName),
186
                'action' => Column::RENAME
187
            ];
188
        }
189
    }
190
191
    /**
192
     * Drops the column
193
     * @param string $name
194
     */
195
    public function dropColumn(string $name)
196
    {
197
        if ($this->action == self::ALTER) {
198
            $this->columns[] = [
199
                'column' => new Column($name),
200
                'action' => Column::DROP
201
            ];
202
        }
203
    }
204
205
    /**
206
     * Adds new index to column
207
     * @param string $columnName
208
     * @param string $indexType
209
     * @param string|null $indexName
210
     */
211
    public function addIndex(string $columnName, string $indexType, string $indexName = null)
212
    {
213
        if ($this->action == self::ALTER) {
214
            $this->columns[] = [
215
                'column' => new Column($columnName),
216
                'action' => Column::ADD_INDEX
217
            ];
218
219
            $this->$indexType($indexName);
220
        }
221
    }
222
223
    /**
224
     * Drops the column index
225
     * @param string $indexName
226
     */
227
    public function dropIndex(string $indexName)
228
    {
229
        if ($this->action == self::ALTER) {
230
            $this->columns[] = [
231
                'column' => (new Column('dummy'))->indexDrop($indexName),
232
                'action' => Column::DROP_INDEX
233
            ];
234
        }
235
    }
236
237
    /**
238
     * Adds columns after specified one
239
     * @param string $columnName
240
     * @return $this
241
     */
242
    public function after(string $columnName): Table
243
    {
244
        $this->columns[$this->columnKey()]['column']->after($columnName);
245
        return $this;
246
    }
247
248
    /**
249
     * Gets the generated query
250
     * @return string
251
     */
252
    public function getSql(): string
253
    {
254
        $sql = '';
255
256
        switch ($this->action) {
257
            case self::CREATE:
258
                $sql = $this->createTableSql();
259
                break;
260
            case self::ALTER:
261
                $sql = $this->alterTableSql();
262
                break;
263
            case self::RENAME:
264
                $sql = $this->renameTableSql();
265
                break;
266
            case self::DROP:
267
                $sql = $this->dropTableSql();
268
                break;
269
        }
270
271
        return $sql;
272
    }
273
274
    /**
275
     * Allows to call methods of Column class
276
     * @param string $method
277
     * @param array|null $arguments
278
     * @return $this
279
     * @throws MigrationException
280
     * @throws LangException
281
     */
282
    public function __call(string $method, ?array $arguments)
283
    {
284
        if (!method_exists(Column::class, $method)) {
285
            throw MigrationException::methodNotDefined($method);
286
        }
287
288
        $this->columns[$this->columnKey()]['column']->{$method}(...$arguments);
289
        return $this;
290
    }
291
292
    /**
293
     * Saves the query
294
     * @throws DatabaseException
295
     */
296
    private function save()
297
    {
298
        $sql = $this->getSql();
299
300
        if ($sql) {
301
            Database::execute($sql);
302
        }
303
    }
304
305
    /**
306
     * Checks if column exists on a table
307
     * @param string $columnName
308
     * @return bool
309
     * @throws DatabaseException
310
     */
311
    private function checkColumnExists(string $columnName): bool
312
    {
313
        $columnIndex = null;
314
315
        $columns = Database::fetchColumns($this->name);
316
317
        foreach ($columns as $index => $column) {
318
            if ($columnName == $column) {
319
                $columnIndex = $index;
320
                break;
321
            }
322
        }
323
324
        return !is_null($columnIndex);
325
    }
326
327
    /**
328
     * Gets the column key
329
     * @return int
330
     */
331
    private function columnKey(): int
332
    {
333
        return (int)array_key_last($this->columns);
334
    }
335
336
}
337