Completed
Push — master ( 1b6594...be51ba )
by Agel_Nash
04:51
created

AbstractDatabase   F

Complexity

Total Complexity 73

Size/Duplication

Total Lines 549
Duplicated Lines 0 %

Test Coverage

Coverage 93.58%

Importance

Changes 0
Metric Value
wmc 73
dl 0
loc 549
ccs 175
cts 187
cp 0.9358
rs 2.459
c 0
b 0
f 0

31 Methods

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

How to fix   Complexity   

Complex Class

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

1
<?php namespace AgelxNash\Modx\Evo\Database;
2
3
abstract class AbstractDatabase implements Interfaces\DatabaseInterface
4
{
5
    use Traits\DebugTrait,
6
        Traits\SupportTrait;
7
8
    /**
9
     * @var array
10
     */
11
    protected $config = [];
12
13
    /**
14
     * @var Interfaces\DriverInterface
15
     */
16
    protected $driver;
17
18
    /**
19
     * @var int
20
     */
21
    protected $safeLoopCount = 1000;
22
23
    /**
24
     * @param $data
25
     * @return $this
26
     */
27 64
    public function setConfig($data)
28
    {
29 64
        $this->config = $data;
30
31 64
        return $this;
32
    }
33
34
    /**
35
     * @param null|string $key
36
     * @return mixed
37
     */
38 64
    public function getConfig($key = null)
39
    {
40 64
        return ($key === null ? $this->config : (isset($this->config[$key]) ? $this->config[$key] : null));
41
    }
42
43
    /**
44
     * @return Interfaces\DriverInterface
45
     * @throws Exceptions\Exception
46
     */
47 45
    public function getDriver()
48
    {
49 45
        return $this->driver;
50
    }
51
52
    /**
53
     * @param string|Interfaces\DriverInterface $driver
54
     * @return Interfaces\DriverInterface
55
     * @throws Exceptions\Exception
56
     */
57 64
    public function setDriver($driver)
58
    {
59 64
        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
0 ignored issues
show
Bug introduced by
Are you sure $driver of type string|AgelxNash\Modx\Ev...erfaces\DriverInterface can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

61
                /** @scrutinizer ignore-type */ $driver . ' should implements the ' . Interfaces\DriverInterface::class
Loading history...
62
            );
63
        }
64
65 64
        if (is_scalar($driver)) {
66 60
            $this->driver = new $driver($this->getConfig());
67
        } else {
68 4
            $this->driver = $driver;
69 4
            $this->config = array_merge($this->config, $driver->getConfig());
0 ignored issues
show
Bug introduced by
The method getConfig() does not exist on AgelxNash\Modx\Evo\Datab...erfaces\DriverInterface. Did you maybe mean getConnect()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
            $this->config = array_merge($this->config, $driver->/** @scrutinizer ignore-call */ getConfig());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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