Passed
Pull Request — master (#190)
by Arman
02:47
created

Table::after()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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