Passed
Push — master ( 43827d...146f8a )
by Agel_Nash
02:46
created

Database::alterTable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php namespace AgelxNash\Modx\Evo\Database;
2
3
class Database implements Interfaces\DatabaseInterface
4
{
5
    use Traits\DebugTrait,
6
        Traits\SupportTrait;
7
8
    /**
9
     * @var array
10
     */
11
    protected $config = [];
12
13
    /**
14
     * @var Drivers\MySqliDriver
15
     */
16
    protected $driver;
17
18
    /**
19
     * @var int
20
     */
21
    protected $safeLoopCount = 1000;
22
23
    /**
24
     * @param string $host
25
     * @param string $base
26
     * @param string $user
27
     * @param string $pass
28
     * @param string $prefix
29
     * @param string $charset
30
     * @param string $method
31
     * @param string $driver
32
     * @throws Exceptions\Exception
33
     */
34 40
    public function __construct(
35
        $host = '',
36
        $base = '',
37
        $user = '',
38
        $pass = '',
39
        $prefix = '',
40
        $charset = 'utf8mb4',
41
        $method = 'SET CHARACTER SET',
42
        $driver = Drivers\MySqliDriver::class
43
    ) {
44 40
        $base = trim($base, '`');
45
46 40
        $this->setConfig(compact(
47 40
            'host',
48 40
            'base',
49 40
            'user',
50 40
            'pass',
51 40
            'prefix',
52 40
            'charset',
53 40
            'method'
54
        ));
55
56 40
        if (! \in_array(Interfaces\DriverInterface::class, class_implements($driver), true)) {
57 1
            throw new Exceptions\DriverException(
58 1
                $driver . ' should implements the ' . Interfaces\DriverInterface::class
59
            );
60
        }
61
62 40
        $this->driver = new $driver(
63 40
            $this->getConfig()
64
        );
65 40
    }
66
67
    /**
68
     * @param $data
69
     * @return $this
70
     */
71 40
    public function setConfig($data) : self
72
    {
73 40
        $this->config = $data;
74
75 40
        return $this;
76
    }
77
78
    /**
79
     * @param null|string $key
80
     * @return mixed
81
     */
82 40
    public function getConfig($key = null)
83
    {
84 40
        return ($key === null ? $this->config : ($this->config[$key] ?? null));
85
    }
86
87
    /**
88
     * @return Interfaces\DriverInterface
89
     * @throws Exceptions\Exception
90
     */
91 22
    public function getDriver() : Interfaces\DriverInterface
92
    {
93 22
        return $this->driver;
94
    }
95
96
    /**
97
     * @return mixed
98
     * @throws Exceptions\Exception
99
     */
100 21
    public function connect()
101
    {
102 21
        $tStart = microtime(true);
103
104 21
        $out = $this->getDriver()->connect();
105
106 20
        $totalTime = microtime(true) - $tStart;
107 20
        if ($this->isDebug()) {
108 20
            $this->connectionTime = $totalTime;
109
        }
110
111 20
        $this->setCharset($this->getConfig('charset'), $this->getConfig('method'));
112
113 20
        return $out;
114
    }
115
116
    /**
117
     * @return $this
118
     */
119 1
    public function disconnect() : self
120
    {
121 1
        $this->getDriver()->disconnect();
122
123 1
        $this->connectionTime = 0;
124 1
        $this->flushExecutedQuery();
125
126 1
        return $this;
127
    }
128
129
    /**
130
     * @param string|array $data
131
     * @param int $safeCount
132
     * @return array|string
133
     * @throws Exceptions\Exception
134
     */
135 1
    public function escape($data, $safeCount = 0)
136
    {
137 1
        $safeCount++;
138 1
        if ($this->safeLoopCount < $safeCount) {
139 1
            throw new Exceptions\TooManyLoopsException("Too many loops '{$safeCount}'");
140
        }
141 1
        if (\is_array($data)) {
142 1
            if (\count($data) === 0) {
143
                $data = '';
144
            } else {
145 1
                foreach ($data as $i => $v) {
146 1
                    $data[$i] = $this->escape($v, $safeCount);
147
                }
148
            }
149
        } else {
150 1
            $data = $this->getDriver()->escape($data);
151
        }
152
153 1
        return $data;
154
    }
155
156
    /**
157
     * @param mixed $sql
158
     * @return mixed
159
     * @throws Exceptions\Exception
160
     */
161 20
    public function query($sql)
162
    {
163 20
        $tStart = microtime(true);
164 20
        if (\is_array($sql)) {
165 1
            $sql = implode("\n", $sql);
166
        }
167 20
        $this->lastQuery = $sql;
168
169 20
        $result = $this->getDriver()->query($this->getLastQuery());
170
171 20
        if ($result === false) {
172
            $this->checkLastError($this->getLastQuery());
173
        } else {
174 20
            $tend = microtime(true);
175 20
            $totalTime = $tend - $tStart;
176 20
            $this->queryTime += $totalTime;
177 20
            if ($this->isDebug()) {
178 20
                $this->collectQuery(
179 20
                    $result,
180 20
                    $this->getLastQuery(),
181 20
                    $this->executedQueries + 1,
182 20
                    $totalTime
183
                );
184
            }
185 20
            $this->executedQueries++;
186
187 20
            return $result;
188
        }
189
        return false;
190
    }
191
192
    /**
193
     * @param string $table
194
     * @param array|string $where
195
     * @param string $orderBy
196
     * @param string $limit
197
     * @return mixed
198
     * @throws Exceptions\Exception
199
     */
200 1
    public function delete($table, $where = '', $orderBy = '', $limit = '')
201
    {
202 1
        $table = $this->prepareFrom($table);
203 1
        $where = $this->prepareWhere($where);
204 1
        $orderBy = $this->prepareOrder($orderBy);
205 1
        $limit = $this->prepareOrder($limit);
206
207 1
        return $this->query("DELETE FROM {$table} {$where} {$orderBy} {$limit}");
208
    }
209
210
    /**
211
     * @param array|string $fields
212
     * @param array|string $tables
213
     * @param array|string $where
214
     * @param string $orderBy
215
     * @param string $limit
216
     * @return mixed
217
     * @throws Exceptions\Exception
218
     */
219 3
    public function select($fields, $tables, $where = '', $orderBy = '', $limit = '')
220
    {
221 3
        $fields = $this->prepareFields($fields);
222 3
        $tables = $this->prepareFrom($tables, true);
223 3
        $where = $this->prepareWhere($where);
224 3
        $orderBy = $this->prepareOrder($orderBy);
225 3
        $limit = $this->prepareLimit($limit);
226
227 3
        return $this->query("SELECT {$fields} FROM {$tables} {$where} {$orderBy} {$limit}");
228
    }
229
230
    /**
231
     * @param array|string $values
232
     * @param string $table
233
     * @param array|string $where
234
     * @return mixed
235
     * @throws Exceptions\Exception
236
     */
237 2
    public function update($values, string $table, $where = '')
238
    {
239 2
        $table = $this->prepareFrom($table);
240 2
        $values = $this->prepareValuesSet($values);
241 2
        if (mb_strtoupper(mb_substr($values, 0, 4)) !== 'SET ') {
242 2
            $values = 'SET ' . $values;
243
        }
244 2
        $where = $this->prepareWhere($where);
245
246 2
        return $this->query("UPDATE {$table} {$values} {$where}");
247
    }
248
249
    /**
250
     * @param array|string $fields
251
     * @param string $table
252
     * @param array|string $fromFields
253
     * @param string $fromTable
254
     * @param array|string $where
255
     * @param string $limit
256
     * @return mixed
257
     * @throws Exceptions\Exception
258
     */
259 4
    public function insert(
260
        $fields,
261
        string $table,
262
        $fromFields = '*',
263
        string $fromTable = '',
264
        $where = '',
265
        string $limit = ''
266
    ) {
267 4
        $table = $this->prepareFrom($table);
268
269 4
        $useFields = null;
270 4
        $lid = null;
271
272 4
        if (\is_array($fields)) {
273 4
            $useFields = empty($fromTable) ?
274 3
                $this->prepareValues($fields) :
275 4
                $this->prepareFields($fields, true);
276
        } else {
277 2
            $useFields = $fields;
278
        }
279
280 4
        if (empty($useFields) || ! \is_scalar($useFields) || ($useFields === '*' && ! empty($fromTable))) {
281
            throw (new Exceptions\InvalidFieldException('Invalid insert fields'))
282
                ->setData($fields);
283
        }
284
285 4
        if (empty($fromTable)) {
286 3
            $this->query("INSERT INTO {$table} {$useFields}");
287
        } else {
288 1
            if (empty($fromFields) || $fromFields === '*') {
289 1
                $fromFields = $this->prepareFields($fields, true);
290
            } else {
291 1
                $fromFields = $this->prepareFields($fromFields, true);
292
            }
293
294 1
            $where = $this->prepareWhere($where);
295 1
            $limit = $this->prepareLimit($limit);
296
297 1
            $lid = $this->query(
298 1
                "INSERT INTO {$table} ({$useFields}) SELECT {$fromFields} FROM {$fromTable} {$where} {$limit}"
299
            );
300
        }
301
302 4
        if ($lid === null && ($lid = $this->getInsertId()) === false) {
303
            throw new Exceptions\GetDataException("Couldn't get last insert key!");
304
        }
305
306 4
        return $this->convertValue($lid);
307
    }
308
309
    /**
310
     * @param string|array $fields
311
     * @param string $table
312
     * @param array|string $where
313
     * @return mixed
314
     * @throws Exceptions\Exception
315
     */
316 1
    public function save($fields, string $table, $where = '')
317
    {
318 1
        if ($where === '') {
319 1
            $mode = 'insert';
320
        } else {
321 1
            $result = $this->select('*', $table, $where);
322
323 1
            if ($this->getRecordCount($result) === 0) {
324 1
                $mode = 'insert';
325
            } else {
326 1
                $mode = 'update';
327
            }
328
        }
329
330 1
        return ($mode === 'insert') ? $this->insert($fields, $table) : $this->update($fields, $table, $where);
331
    }
332
333
    /**
334
     * @param $result
335
     * @return bool
336
     */
337 1
    public function isResult($result) : bool
338
    {
339 1
        return $this->getDriver()->isResult($result);
340
    }
341
342
    /**
343
     * @param $result
344
     * @return int
345
     */
346 1
    public function numFields($result) : int
347
    {
348 1
        return $this->getDriver()->numFields($result);
349
    }
350
351
    /**
352
     * @param $result
353
     * @param int $col
354
     * @return string|null
355
     */
356 1
    public function fieldName($result, $col = 0) :? string
357
    {
358 1
        return $this->getDriver()->fieldName($result, $col);
359
    }
360
361
    /**
362
     * @param string $charset
363
     * @param string|null $method
364
     * @return bool
365
     * @throws Exceptions\Exception
366
     */
367 20
    public function setCharset(string $charset, $method = null) : bool
368
    {
369 20
        if ($method !== null) {
370 20
            $this->query($method . ' ' . $charset);
371
        }
372
373 20
        $tStart = microtime(true);
374
375 20
        $result = $this->getDriver()->setCharset($charset);
376
377 20
        $this->queryTime += microtime(true) - $tStart;
378
379 20
        return $result;
380
    }
381
382
    /**
383
     * @param string $name
384
     * @return bool
385
     * @throws Exceptions\Exception
386
     */
387
    public function selectDb(string $name) : bool
388
    {
389
        $tStart = microtime(true);
390
391
        $result = $this->getDriver()->selectDb($name);
392
393
        $this->queryTime += microtime(true) - $tStart;
394
395
        return $result;
396
    }
397
398
    /**
399
     * @param $result
400
     * @return int
401
     */
402 10
    public function getRecordCount($result) : int
403
    {
404 10
        return $this->getDriver()->getRecordCount($result);
405
    }
406
407
    /**
408
     * @param $result
409
     * @param string $mode
410
     * @return array|mixed|object|\stdClass
411
     * @throws Exceptions\Exception
412
     */
413 2
    public function getRow($result, $mode = 'assoc')
414
    {
415 2
        if (\is_scalar($result)) {
416 1
            $result = $this->query($result);
417
        }
418
419 2
        return $this->getDriver()->getRow($result, $mode);
420
    }
421
422
    /**
423
     * @param string string $name
424
     * @param mixed $result
425
     * @return array
426
     * @throws Exceptions\Exception
427
     */
428 3
    public function getColumn(string $name, $result) : array
429
    {
430 3
        if (\is_scalar($result)) {
431 3
            $result = $this->query($result);
432
        }
433
434 3
        return $this->getDriver()->getColumn($name, $result);
435
    }
436
437
    /**
438
     * @param mixed $result
439
     * @return array
440
     * @throws Exceptions\Exception
441
     */
442 1
    public function getColumnNames($result) : array
443
    {
444 1
        if (\is_scalar($result)) {
445
            $result = $this->query($result);
446
        }
447
448 1
        return $this->getDriver()->getColumnNames($result);
449
    }
450
451
    /**
452
     * @param mixed $result
453
     * @return bool|mixed
454
     * @throws Exceptions\Exception
455
     */
456 3
    public function getValue($result)
457
    {
458 3
        if (\is_scalar($result)) {
459 3
            $result = $this->query($result);
460
        }
461
462 3
        return $this->convertValue(
463 3
            $this->getDriver()->getValue($result)
464
        );
465
    }
466
467
    /**
468
     * @param string $table
469
     * @return array
470
     * @throws Exceptions\Exception
471
     */
472 1
    public function getTableMetaData(string $table) : array
473
    {
474 1
        $metadata = [];
475 1
        if (! empty($table)) {
476 1
            $sql = 'SHOW FIELDS FROM ' . $table;
477 1
            $result = $this->query($sql);
478 1
            $metadata = $this->getDriver()->getTableMetaData($result);
479
        }
480
481 1
        return $metadata;
482
    }
483
484
    /**
485
     * @param $result
486
     * @param bool $index
487
     * @return array
488
     * @throws Exceptions\Exception
489
     */
490 1
    public function makeArray($result, bool $index = false) : array
491
    {
492 1
        $rsArray = [];
493 1
        $iterator = 0;
494 1
        while ($row = $this->getRow($result)) {
495 1
            $returnIndex = $index !== false && isset($row[$index]) ? $row[$index] : $iterator;
496 1
            $rsArray[$returnIndex] = $row;
497 1
            $iterator++;
498
        }
499
500 1
        return $rsArray;
501
    }
502
503
    /**
504
     * @return string
505
     * @throws Exceptions\Exception
506
     */
507 1
    public function getVersion() : string
508
    {
509 1
        return $this->getDriver()->getVersion();
510
    }
511
512
    /**
513
     * @param string $table
514
     * @return mixed
515
     * @throws Exceptions\Exception
516
     */
517 1
    public function optimize(string $table)
518
    {
519 1
        $result = $this->query('OPTIMIZE TABLE ' . $table);
520 1
        if ($result !== false) {
521 1
            $result = $this->alterTable($table);
522
        }
523
524 1
        return $result;
525
    }
526
527
    /**
528
     * @param string $table
529
     * @return mixed
530
     * @throws Exceptions\Exception
531
     */
532 2
    public function alterTable(string $table)
533
    {
534 2
        return $this->query('ALTER TABLE ' . $table);
535
    }
536
537
    /**
538
     * @param string $table
539
     * @return mixed
540
     * @throws Exceptions\Exception
541
     */
542 1
    public function truncate(string $table)
543
    {
544 1
        return $this->query('TRUNCATE ' . $table);
545
    }
546
547
    /**
548
     * @return mixed
549
     * @throws Exceptions\Exception
550
     */
551 3
    public function getInsertId()
552
    {
553 3
        return $this->convertValue(
554 3
            $this->getDriver()->getInsertId()
555
        );
556
    }
557
558
    /**
559
     * @return int
560
     * @throws Exceptions\Exception
561
     */
562 20
    public function getAffectedRows() : int
563
    {
564 20
        return $this->getDriver()->getAffectedRows();
565
    }
566
}
567