Completed
Push — master ( 348990...cde96e )
by Agel_Nash
03:07
created

Database   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 574
Duplicated Lines 0 %

Test Coverage

Coverage 93.85%

Importance

Changes 0
Metric Value
dl 0
loc 574
ccs 183
cts 195
cp 0.9385
rs 2.6315
c 0
b 0
f 0
wmc 71

31 Methods

Rating   Name   Duplication   Size   Complexity  
A disconnect() 0 8 1
A save() 0 15 4
A getRecordCount() 0 3 1
A getAffectedRows() 0 3 1
A getColumnNames() 0 6 2
A fieldName() 0 3 1
A setCharset() 0 9 1
B __construct() 0 32 2
A delete() 0 9 2
A getConfig() 0 3 2
A getVersion() 0 3 1
A numFields() 0 3 1
A selectDb() 0 9 1
A getColumn() 0 7 2
A getValue() 0 8 2
A connect() 0 18 2
A getInsertId() 0 4 1
B escape() 0 19 5
A optimize() 0 8 3
C insert() 0 49 13
A select() 0 9 1
A getRow() 0 7 2
A makeArray() 0 11 4
A alterTable() 0 5 2
B query() 0 31 4
A truncate() 0 5 2
A isResult() 0 3 1
A setConfig() 0 5 1
A update() 0 11 3
A getTableMetaData() 0 10 2
A getDriver() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Database 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 Database, and based on these observations, apply Extract Interface, too.

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