Completed
Push — develop ( cb7ecf...5e631f )
by Dmytro
17s
created

Database::insert()   D

Complexity

Conditions 9
Paths 13

Size

Total Lines 37
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 28
nc 13
nop 6
dl 0
loc 37
rs 4.909
c 0
b 0
f 0
1
<?php namespace EvolutionCMS;
2
3
use mysqli;
4
use mysqli_result;
5
6
class Database implements Interfaces\DatabaseInterface
0 ignored issues
show
Coding Style introduced by
The property $_dbconnectionmethod is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
7
{
8
    /**
9
     * @var mysqli
10
     */
11
    public $conn;
12
    public $config;
13
    public $lastQuery;
14
    public $isConnected;
15
    public $_dbconnectionmethod;
16
17
    /**
18
     * DBAPI constructor.
19
     *
20
     * @param string $host
21
     * @param string $dbase
22
     * @param string $uid
23
     * @param string $pwd
24
     * @param null|string $pre
25
     * @param string $charset
26
     * @param string $connection_method
27
     */
28
    public function __construct(
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style Naming introduced by
The parameter $connection_method is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
29
        $host = '',
30
        $dbase = '',
31
        $uid = '',
32
        $pwd = '',
33
        $pre = null,
34
        $charset = '',
35
        $connection_method = 'SET CHARACTER SET'
36
    ) {
37
        $this->config['host'] = $host ? $host : $GLOBALS['database_server'];
38
        $this->config['dbase'] = $dbase ? $dbase : $GLOBALS['dbase'];
39
        $this->config['user'] = $uid ? $uid : $GLOBALS['database_user'];
40
        $this->config['pass'] = $pwd ? $pwd : $GLOBALS['database_password'];
41
        $this->config['charset'] = $charset ? $charset : $GLOBALS['database_connection_charset'];
42
        $this->config['connection_method'] = $this->_dbconnectionmethod = (isset($GLOBALS['database_connection_method']) ? $GLOBALS['database_connection_method'] : $connection_method);
43
        $this->config['table_prefix'] = ($pre !== null) ? $pre : $GLOBALS['table_prefix'];
44
    }
45
46
    /**
47
     * @param string $host
48
     * @param string $dbase
49
     * @param string $uid
50
     * @param string $pwd
51
     * @return mysqli
0 ignored issues
show
Documentation introduced by
Should the return type not be mysqli|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
52
     */
53
    public function connect($host = '', $dbase = '', $uid = '', $pwd = '')
0 ignored issues
show
Coding Style introduced by
connect uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
54
    {
55
        $modx = evolutionCMS();
56
        $uid = $uid ? $uid : $this->config['user'];
57
        $pwd = $pwd ? $pwd : $this->config['pass'];
58
        $host = $host ? $host : $this->config['host'];
59
        $dbase = $dbase ? $dbase : $this->config['dbase'];
60
        $dbase = trim($dbase, '`'); // remove the `` chars
61
        $charset = $this->config['charset'];
62
        $connection_method = $this->config['connection_method'];
63
        $tstart = $modx->getMicroTime();
64
        $safe_count = 0;
65
        do {
66
            $this->conn = new mysqli($host, $uid, $pwd, $dbase);
67
            if ($this->conn->connect_error) {
68
                $this->conn = null;
69
                if (isset($modx->config['send_errormail']) && $modx->config['send_errormail'] !== '0') {
70
                    if ($modx->config['send_errormail'] <= 2) {
71
                        $logtitle = 'Failed to create the database connection!';
72
                        $request_uri = $modx->getPhpCompat()->htmlspecialchars($_SERVER['REQUEST_URI']);
73
                        $ua = $modx->getPhpCompat()->htmlspecialchars($_SERVER['HTTP_USER_AGENT']);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ua. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
74
                        $referer = $modx->getPhpCompat()->htmlspecialchars($_SERVER['HTTP_REFERER']);
75
                        $modx->sendmail(array(
76
                            'subject' => 'Missing to create the database connection! from ' . $modx->config['site_name'],
77
                            'body'    => "{$logtitle}\n{$request_uri}\n{$ua}\n{$referer}",
78
                            'type'    => 'text'
79
                        ));
80
                    }
81
                }
82
                sleep(1);
83
                $safe_count++;
84
            }
85
        } while (!$this->conn && $safe_count < 3);
86
        if ($this->conn instanceof mysqli) {
87
            $this->conn->query("{$connection_method} {$charset}");
88
            $tend = $modx->getMicroTime();
89
            $totaltime = $tend - $tstart;
90
            if ($modx->dumpSQL) {
91
                $modx->queryCode .= "<fieldset style='text-align:left'><legend>Database connection</legend>" . sprintf("Database connection was created in %2.4f s",
92
                        $totaltime) . "</fieldset><br />";
93
            }
94
            $this->conn->set_charset($this->config['charset']);
95
            $this->isConnected = true;
96
            $modx->queryTime += $totaltime;
97
        } else {
98
            $modx->messageQuit("Failed to create the database connection!");
99
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method connect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
100
        }
101
        return $this->conn;
102
    }
103
104
    /**
105
     * @return void
106
     */
107
    public function disconnect()
108
    {
109
        $this->conn->close();
110
        $this->conn = null;
111
        $this->isConnected = false;
112
    }
113
114
    /**
115
     * @param array|string $s
116
     * @param int $safeCount
117
     * @return array|string
118
     */
119
    public function escape($s, $safeCount = 0)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $s. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
120
    {
121
        $safeCount++;
122
        if (1000 < $safeCount) {
123
            exit("Too many loops '{$safeCount}'");
0 ignored issues
show
Coding Style Compatibility introduced by
The method escape() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
124
        }
125
        if ( ! ($this->conn instanceof mysqli)) {
126
            $this->connect();
127
        }
128
        if (is_array($s)) {
129
            if (count($s) === 0) {
130
                $s = '';
131
            } else {
132
                foreach ($s as $i => $v) {
133
                    $s[$i] = $this->escape($v, $safeCount);
134
                }
135
            }
136
        } else {
137
            $s = $this->conn->escape_string($s);
138
        }
139
140
        return $s;
141
    }
142
143
    /**
144
     * @param string|array|mysqli_result $sql
145
     * @param bool $watchError
146
     * @return bool|mysqli_result
147
     */
148
    public function query($sql, $watchError = true)
149
    {
150
        $modx = evolutionCMS();
151
        if ( ! ($this->conn instanceof mysqli)) {
152
            $this->connect();
153
        }
154
        $tStart = $modx->getMicroTime();
155
        if (is_array($sql)) {
156
            $sql = implode("\n", $sql);
157
        }
158
        $this->lastQuery = $sql;
159
        if (!($result = $this->conn->query($sql))) {
160
            if (!$watchError) {
161
                return false;
162
            }
163
            switch (mysqli_errno($this->conn)) {
164
                case 1054:
165
                case 1060:
166
                case 1061:
167
                case 1062:
168
                case 1091:
169
                    break;
170
                default:
171
                    $modx->messageQuit('Execution of a query to the database failed - ' . $this->getLastError(), $sql);
0 ignored issues
show
Bug introduced by
It seems like $sql defined by parameter $sql on line 148 can also be of type object<mysqli_result>; however, EvolutionCMS\Core::messageQuit() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
172
            }
173
        } else {
174
            $tend = $modx->getMicroTime();
175
            $totalTime = $tend - $tStart;
176
            $modx->queryTime += $totalTime;
177
            if ($modx->dumpSQL) {
178
                $debug = debug_backtrace();
179
                array_shift($debug);
180
                $debug_path = array();
181
                foreach ($debug as $line) {
182
                    $debug_path[] = $line['function'];
183
                }
184
                $debug_path = implode(' > ', array_reverse($debug_path));
185
                $modx->queryCode .= "<fieldset style='text-align:left'><legend>Query " . ($modx->executedQueries + 1) . " - " . sprintf("%2.2f ms",
186
                        $totalTime * 1000) . "</legend>";
187
                $modx->queryCode .= $sql . '<br><br>';
188
                if ($modx->event->name) {
189
                    $modx->queryCode .= 'Current Event  => ' . $modx->event->name . '<br>';
190
                }
191
                if ($modx->event->activePlugin) {
192
                    $modx->queryCode .= 'Current Plugin => ' . $modx->event->activePlugin . '<br>';
193
                }
194
                if ($modx->currentSnippet) {
195
                    $modx->queryCode .= 'Current Snippet => ' . $modx->currentSnippet . '<br>';
196
                }
197
                if (stripos($sql, 'select') === 0) {
198
                    $modx->queryCode .= 'Record Count => ' . $this->getRecordCount($result) . '<br>';
199
                } else {
200
                    $modx->queryCode .= 'Affected Rows => ' . $this->getAffectedRows() . '<br>';
201
                }
202
                $modx->queryCode .= 'Functions Path => ' . $debug_path . '<br>';
203
                $modx->queryCode .= "</fieldset><br />";
204
            }
205
            $modx->executedQueries++;
206
207
            return $result;
208
        }
209
        return false;
210
    }
211
212
    /**
213
     * @param string $from
214
     * @param string $where
215
     * @param string $orderBy
216
     * @param string $limit
217
     * @return bool|mysqli_result
218
     */
219
    public function delete($from, $where = '', $orderBy = '', $limit = '')
220
    {
221
        $modx = evolutionCMS();
222
        $out = false;
223
        if (!$from) {
224
            $modx->messageQuit("Empty \$from parameters in DBAPI::delete().");
225
        } else {
226
            $from = $this->replaceFullTableName($from);
227
            $where = trim($where);
228
            $orderBy = trim($orderBy);
229
            $limit = trim($limit);
230
            if ($where !== '' && stripos($where, 'WHERE') !== 0) {
231
                $where = "WHERE {$where}";
232
            }
233
            if ($orderBy !== '' && stripos($orderBy, 'ORDER BY') !== 0) {
234
                $orderBy = "ORDER BY {$orderBy}";
235
            }
236
            if ($limit !== '' && stripos($limit, 'LIMIT') !== 0) {
237
                $limit = "LIMIT {$limit}";
238
            }
239
240
            $out = $this->query("DELETE FROM {$from} {$where} {$orderBy} {$limit}");
241
        }
242
        return $out;
243
    }
244
245
    /**
246
     * @param string|array $fields
247
     * @param string|array $from
248
     * @param string|array $where
249
     * @param string $orderBy
250
     * @param string $limit
251
     * @return bool|mysqli_result
252
     */
253
    public function select($fields = "*", $from = "", $where = "", $orderBy = "", $limit = "")
254
    {
255
        $modx = evolutionCMS();
256
257
        if (is_array($fields)) {
258
            $fields = $this->_getFieldsStringFromArray($fields);
259
        }
260
        if (is_array($from)) {
261
            $from = $this->_getFromStringFromArray($from);
262
        }
263
        if (is_array($where)) {
264
            $where = implode(' ', $where);
265
        }
266
267
        if (!$from) {
268
            $modx->messageQuit("Empty \$from parameters in DBAPI::select().");
269
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method select() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
270
        }
271
272
        $fields = $this->replaceFullTableName($fields);
273
        $from = $this->replaceFullTableName($from);
274
        $where = trim($where);
275
        $orderBy = trim($orderBy);
276
        $limit = trim($limit);
277
        if ($where !== '' && stripos($where, 'WHERE') !== 0) {
278
            $where = "WHERE {$where}";
279
        }
280
        if ($orderBy !== '' && stripos($orderBy, 'ORDER') !== 0) {
281
            $orderBy = "ORDER BY {$orderBy}";
282
        }
283
        if ($limit !== '' && stripos($limit, 'LIMIT') !== 0) {
284
            $limit = "LIMIT {$limit}";
285
        }
286
287
        return $this->query("SELECT {$fields} FROM {$from} {$where} {$orderBy} {$limit}");
288
    }
289
290
    /**
291
     * @param array|string $fields
292
     * @param $table
293
     * @param string $where
294
     * @return bool|mysqli_result
295
     */
296
    public function update($fields, $table, $where = "")
297
    {
298
        $modx = evolutionCMS();
299
        $out = false;
300
        if (!$table) {
301
            $modx->messageQuit('Empty '.$table.' parameter in DBAPI::update().');
302
        } else {
303
            $table = $this->replaceFullTableName($table);
304
            if (is_array($fields)) {
305
                foreach ($fields as $key => $value) {
306
                    if ($value === null || strtolower($value) === 'null') {
307
                        $f = 'NULL';
308
                    } else {
309
                        $f = "'" . $value . "'";
310
                    }
311
                    $fields[$key] = "`{$key}` = " . $f;
312
                }
313
                $fields = implode(',', $fields);
314
            }
315
            $where = trim($where);
316
            if ($where !== '' && stripos($where, 'WHERE') !== 0) {
317
                $where = 'WHERE '.$where;
318
            }
319
320
            return $this->query('UPDATE '.$table.' SET '.$fields.' '.$where);
321
        }
322
        return $out;
323
    }
324
325
    /**
326
     * @param string|array $fields
327
     * @param string $intotable
328
     * @param string $fromfields
329
     * @param string $fromtable
330
     * @param string $where
331
     * @param string $limit
332
     * @return mixed
333
     */
334
    public function insert($fields, $intotable, $fromfields = "*", $fromtable = "", $where = "", $limit = "")
335
    {
336
        $modx = evolutionCMS();
337
        $out = false;
338
        if (!$intotable) {
339
            $modx->messageQuit("Empty \$intotable parameters in DBAPI::insert().");
340
        } else {
341
            $intotable = $this->replaceFullTableName($intotable);
342
            if (!is_array($fields)) {
343
                $this->query("INSERT INTO {$intotable} {$fields}");
344
            } else {
345
                if (empty($fromtable)) {
346
                    $fields = "(`" . implode("`, `", array_keys($fields)) . "`) VALUES('" . implode("', '",
347
                            array_values($fields)) . "')";
348
                    $this->query("INSERT INTO {$intotable} {$fields}");
349
                } else {
350
                    $fromtable = $this->replaceFullTableName($fromtable);
351
                    $fields = "(" . implode(",", array_keys($fields)) . ")";
352
                    $where = trim($where);
353
                    $limit = trim($limit);
354
                    if ($where !== '' && stripos($where, 'WHERE') !== 0) {
355
                        $where = "WHERE {$where}";
356
                    }
357
                    if ($limit !== '' && stripos($limit, 'LIMIT') !== 0) {
358
                        $limit = "LIMIT {$limit}";
359
                    }
360
                    $this->query("INSERT INTO {$intotable} {$fields} SELECT {$fromfields} FROM {$fromtable} {$where} {$limit}");
361
                }
362
            }
363
            if (($lid = $this->getInsertId()) === false) {
364
                $modx->messageQuit("Couldn't get last insert key!");
365
            }
366
367
            $out = $lid;
368
        }
369
        return $out;
370
    }
371
372
    /**
373
     * @param $fields
374
     * @param $table
375
     * @param string $where
376
     * @return bool|mixed|mysqli_result
377
     */
378
    public function save($fields, $table, $where = '')
379
    { // This is similar to "replace into table".
380
381
        if ($where === '') {
382
            $mode = 'insert';
383
        } elseif ($this->getRecordCount($this->select('*', $table, $where)) === 0) {
0 ignored issues
show
Bug introduced by
It seems like $this->select('*', $table, $where) targeting EvolutionCMS\Database::select() can also be of type boolean; however, EvolutionCMS\Database::getRecordCount() does only seem to accept object<mysqli_result>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
384
            $mode = 'insert';
385
        } else {
386
            $mode = 'update';
387
        }
388
389
        return ($mode === 'insert') ? $this->insert($fields, $table) : $this->update($fields, $table, $where);
390
    }
391
392
    /**
393
     * @param mixed $rs
394
     * @return bool
395
     */
396
    public function isResult($rs)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
397
    {
398
        return $rs instanceof mysqli_result;
399
    }
400
401
    /**
402
     * @param mysqli_result $rs
403
     */
404
    public function freeResult($rs)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
405
    {
406
        $rs->free_result();
407
    }
408
409
    /**
410
     * @param mysqli_result $rs
411
     * @return mixed
412
     */
413
    public function numFields($rs)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
414
    {
415
        return $rs->field_count;
416
    }
417
418
    /**
419
     * @param mysqli_result $rs
420
     * @param int $col
421
     * @return string|null
422
     */
423
    public function fieldName($rs, $col = 0)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
424
    {
425
        $field = $rs->fetch_field_direct($col);
426
427
        return isset($field->name) ? $field->name : null;
428
    }
429
430
    /**
431
     * @param $name
432
     */
433
    public function selectDb($name)
434
    {
435
        $this->conn->select_db($name);
436
    }
437
438
439
    /**
440
     * @param null|mysqli $conn
441
     * @return mixed
442
     */
443
    public function getInsertId($conn = null)
444
    {
445
        if (! ($conn instanceof mysqli)) {
446
            $conn =& $this->conn;
447
        }
448
449
        return $conn->insert_id;
450
    }
451
452
    /**
453
     * @param null|mysqli $conn
454
     * @return int
455
     */
456
    public function getAffectedRows($conn = null)
457
    {
458
        if (! ($conn instanceof mysqli)) {
459
            $conn =& $this->conn;
460
        }
461
462
        return $conn->affected_rows;
463
    }
464
465
    /**
466
     * @param null|mysqli $conn
467
     * @return string
468
     */
469
    public function getLastError($conn = null)
470
    {
471
        if (! ($conn instanceof mysqli)) {
472
            $conn =& $this->conn;
473
        }
474
475
        return $conn->error;
476
    }
477
478
    /**
479
     * @param mysqli_result $ds
480
     * @return int
481
     */
482
    public function getRecordCount($ds)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ds. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
483
    {
484
        return ($ds instanceof mysqli_result) ? $ds->num_rows : 0;
485
    }
486
487
    /**
488
     * @param mysqli_result $ds
489
     * @param string $mode
490
     * @return array|bool|mixed|object|stdClass
491
     */
492
    public function getRow($ds, $mode = 'assoc')
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ds. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
493
    {
494
        $out = false;
495
        if ($ds instanceof mysqli_result) {
496
            switch($mode){
497
                case 'assoc':
498
                    $out = $ds->fetch_assoc();
499
                    break;
500
                case 'num':
501
                    $out = $ds->fetch_row();
502
                    break;
503
                case 'object':
504
                    $out = $ds->fetch_object();
505
                    break;
506
                case 'both':
507
                    $out = $ds->fetch_array(MYSQLI_BOTH);
508
                    break;
509
                default:
510
                    $modx = evolutionCMS();
511
                    $modx->messageQuit("Unknown get type ($mode) specified for fetchRow - must be empty, 'assoc', 'num' or 'both'.");
512
513
            }
514
        }
515
        return $out;
516
    }
517
518
    /**
519
     * @param $name
520
     * @param mysqli_result|string $dsq
521
     * @return array
522
     */
523
    public function getColumn($name, $dsq)
524
    {
525
        $col = array();
526
        if ( ! ($dsq instanceof mysqli_result)) {
527
            $dsq = $this->query($dsq);
528
        }
529
        if ($dsq) {
530
            while ($row = $this->getRow($dsq)) {
0 ignored issues
show
Bug introduced by
It seems like $dsq can also be of type boolean; however, EvolutionCMS\Database::getRow() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
531
                $col[] = $row[$name];
532
            }
533
        }
534
535
        return $col;
536
    }
537
538
    /**
539
     * @param mysqli_result|string $dsq
540
     * @return array
541
     */
542
    public function getColumnNames($dsq)
543
    {
544
        $names = array();
545
        if ( ! ($dsq instanceof mysqli_result)) {
546
            $dsq = $this->query($dsq);
547
        }
548
        if ($dsq) {
549
            $limit = $this->numFields($dsq);
0 ignored issues
show
Bug introduced by
It seems like $dsq can also be of type boolean; however, EvolutionCMS\Database::numFields() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
550
            for ($i = 0; $i < $limit; $i++) {
551
                $names[] = $this->fieldName($dsq, $i);
0 ignored issues
show
Bug introduced by
It seems like $dsq can also be of type boolean; however, EvolutionCMS\Database::fieldName() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
552
            }
553
        }
554
555
        return $names;
556
    }
557
558
    /**
559
     * @param mysqli_result|string $dsq
560
     * @return bool|string|int
561
     */
562
    public function getValue($dsq)
563
    {
564
        $out = false;
565
        if ( ! ($dsq instanceof mysqli_result)) {
566
            $dsq = $this->query($dsq);
567
        }
568
        if ($dsq) {
569
            $r = $this->getRow($dsq, 'num');
0 ignored issues
show
Bug introduced by
It seems like $dsq can also be of type boolean; however, EvolutionCMS\Database::getRow() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $r. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
570
            $out = isset($r[0]) ? $r[0] : false;
571
        }
572
573
        return $out;
574
    }
575
576
    /**
577
     * @param string $table
578
     * @return array
579
     */
580
    public function getTableMetaData($table)
581
    {
582
        $metadata = array();
583
        if (!empty($table) && is_scalar($table)) {
584
            $sql = 'SHOW FIELDS FROM '.$table;
585
            if ($ds = $this->query($sql)) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ds. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
586
                while ($row = $this->getRow($ds)) {
0 ignored issues
show
Bug introduced by
It seems like $ds defined by $this->query($sql) on line 585 can also be of type boolean; however, EvolutionCMS\Database::getRow() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
587
                    $fieldName = $row['Field'];
588
                    $metadata[$fieldName] = $row;
589
                }
590
            }
591
        }
592
593
        return $metadata;
594
    }
595
596
    /**
597
     * @param int $timestamp
598
     * @param string $fieldType
599
     * @return false|string
600
     */
601
    public function prepareDate($timestamp, $fieldType = 'DATETIME')
602
    {
603
        $date = false;
604
        if (!$timestamp === false && $timestamp > 0) {
605
            switch ($fieldType) {
606
                case 'DATE' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
607
                    $date = date('Y-m-d', $timestamp);
608
                    break;
609
                case 'TIME' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
610
                    $date = date('H:i:s', $timestamp);
611
                    break;
612
                case 'YEAR' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
613
                    $date = date('Y', $timestamp);
614
                    break;
615
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
616
                    $date = date('Y-m-d H:i:s', $timestamp);
617
                    break;
618
            }
619
        }
620
621
        return $date;
622
    }
623
624
    /**
625
     * @param string|mysqli_result $rs
626
     * @param bool $index
627
     * @return array
628
     */
629
    public function makeArray($rs = '', $index = false)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
630
    {
631
        $rsArray = array();
632
        if (!$rs) {
633
            return $rsArray;
634
        }
635
        $iterator = 0;
636
        while ($row = $this->getRow($rs)) {
0 ignored issues
show
Bug introduced by
It seems like $rs defined by parameter $rs on line 629 can also be of type string; however, EvolutionCMS\Database::getRow() does only seem to accept object<mysqli_result>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
637
            $returnIndex = $index !== false && isset($row[$index]) ? $row[$index] : $iterator;
638
            $rsArray[$returnIndex] = $row;
639
            $iterator++;
640
        }
641
642
        return $rsArray;
643
    }
644
645
    /**
646
     * @return string
647
     */
648
    public function getVersion()
649
    {
650
        return $this->conn->server_info;
651
    }
652
653
    /**
654
     * @param string $tableName
655
     * @param bool $force
656
     * @return string
657
     */
658
    public function replaceFullTableName($tableName, $force = false)
659
    {
660
        $tableName = trim($tableName);
661
        $dbase = trim($this->config['dbase'], '`');
662
        $prefix = $this->config['table_prefix'];
663
        if ((bool)$force === true) {
664
            $result = "`{$dbase}`.`{$prefix}{$tableName}`";
665
        } elseif (strpos($tableName, '[+prefix+]') !== false) {
666
            $result = preg_replace('@\[\+prefix\+\]([0-9a-zA-Z_]+)@', "`{$dbase}`.`{$prefix}$1`", $tableName);
667
        } else {
668
            $result = $tableName;
669
        }
670
671
        return $result;
672
    }
673
674
    /**
675
     * @param string $table_name
676
     * @return bool|mysqli_result
677
     */
678
    public function optimize($table_name)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $table_name is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
679
    {
680
        $rs = $this->query('OPTIMIZE TABLE '.$table_name);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
681
        if ($rs) {
682
            $rs = $this->query('ALTER TABLE '.$table_name);
683
        }
684
685
        return $rs;
686
    }
687
688
    /**
689
     * @param string $table_name
690
     * @return bool|mysqli_result
691
     */
692
    public function truncate($table_name)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $table_name is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
693
    {
694
        return $this->query('TRUNCATE '.$table_name);
695
    }
696
697
    /**
698
     * @param mysqli_result $result
699
     * @param int $row_number
700
     * @return bool
701
     */
702
    public function dataSeek($result, $row_number)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $row_number is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
703
    {
704
        return $result->data_seek($row_number);
705
    }
706
707
    /**
708
     * @param array $fields
709
     * @return string
710
     */
711
    public function _getFieldsStringFromArray($fields = array())
712
    {
713
714
        if (empty($fields)) {
715
            return '*';
716
        }
717
718
        $_ = array();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $_. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
719
        foreach ($fields as $k => $v) {
720
            if ($k !== $v) {
721
                $_[] = $v.' as '.$k;
722
            } else {
723
                $_[] = $v;
724
            }
725
        }
726
727
        return implode(',', $_);
728
    }
729
730
    /**
731
     * @param array $tables
732
     * @return string
733
     */
734
    public function _getFromStringFromArray($tables = array())
735
    {
736
        $_ = array();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $_. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
737
        foreach ($tables as $k => $v) {
738
            $_[] = $v;
739
        }
740
741
        return implode(' ', $_);
742
    }
743
}
744