Db   B
last analyzed

Complexity

Total Complexity 46

Size/Duplication

Total Lines 362
Duplicated Lines 0 %

Test Coverage

Coverage 47.31%

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 84
c 8
b 0
f 0
dl 0
loc 362
ccs 44
cts 93
cp 0.4731
rs 8.72
wmc 46

19 Methods

Rating   Name   Duplication   Size   Complexity  
A transactionBegin() 0 3 1
A transactionAbort() 0 3 1
A seek() 0 13 2
A free() 0 2 1
A tableNames() 0 10 2
A getLastInsertId() 0 6 5
A haltmsg() 0 7 3
A num_fields() 0 4 1
A lock() 0 2 1
A unlock() 0 2 1
A affectedRows() 0 3 1
A num_rows() 0 3 1
A transactionCommit() 0 3 1
A useDb() 0 3 1
B connect() 0 32 9
A next_record() 0 17 4
B query() 0 37 8
A disconnect() 0 2 1
A selectDb() 0 8 2

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * PDO SQL Related Functionality
4
 * @author Joe Huss <[email protected]>
5
 * @copyright 2025
6
 * @package MyAdmin
7
 * @category SQL
8
 */
9
10
namespace MyDb\Pdo;
11
12
use MyDb\Generic;
13
use MyDb\Db_Interface;
14
use PDO;
15
16
/**
17
 * Db
18
 *
19
 * @access public
20
 */
21
class Db extends Generic implements Db_Interface
22
{
23
    /* public: connection parameters */
24
    public $driver = 'mysql';
25
    public $Rows = [];
26
    /* public: this is an api revision, not a CVS revision. */
27
    public $type = 'pdo';
28
29
    /**
30
     * changes the database we are working with.
31
     *
32
     * @param string $database the name of the database to use
33
     * @return void
34
     */
35 2
    public function selectDb($database)
36
    {
37 2
        $dSN = "{$this->driver}:dbname={$database};host={$this->host}";
38 2
        if ($this->characterSet != '') {
39 2
            $dSN .= ';charset='.$this->characterSet;
40
        }
41 2
        $this->linkId = new PDO($dSN, $this->user, $this->password);
42 2
        $this->database = $database;
43
    }
44
45
46
    /**
47
     * alias function of select_db, changes the database we are working with.
48
     *
49
     * @param string $database the name of the database to use
50
     * @return void
51
     */
52 2
    public function useDb($database)
53
    {
54 2
        $this->selectDb($database);
55
    }
56
57
    /* public: connection management */
58
59
    /**
60
     * Db::connect()
61
     * @param string $database
62
     * @param string $host
63
     * @param string $user
64
     * @param string $password
65
     * @param string $driver
66
     * @return bool|int|PDO
67
     */
68 3
    public function connect($database = '', $host = '', $user = '', $password = '', $driver = 'mysql')
69
    {
70
        /* Handle defaults */
71 3
        if ('' == $database) {
72 3
            $database = $this->database;
73
        }
74 3
        if ('' == $host) {
75 3
            $host = $this->host;
76
        }
77 3
        if ('' == $user) {
78 3
            $user = $this->user;
79
        }
80 3
        if ('' == $password) {
81 3
            $password = $this->password;
82
        }
83 3
        if ('' == $driver) {
84
            $driver = $this->driver;
85
        }
86
        /* establish connection, select database */
87 3
        $dSN = "{$driver}:dbname={$database};host={$host}";
88 3
        if ($this->characterSet != '') {
89 3
            $dSN .= ';charset='.$this->characterSet;
90
        }
91 3
        if ($this->linkId === false) {
0 ignored issues
show
introduced by
The condition $this->linkId === false is always false.
Loading history...
92
            try {
93
                $this->linkId = new PDO($dSN, $user, $password);
94
            } catch (\PDOException $e) {
95
                $this->halt('Connection Failed '.$e->getMessage());
96
                return 0;
97
            }
98
        }
99 3
        return $this->linkId;
100
    }
101
102
    /* This only affects systems not using persistent connections */
103
104
    /**
105
     * Db::disconnect()
106
     * @return void
107
     */
108
    public function disconnect()
109
    {
110
    }
111
112
    /* public: discard the query result */
113
114
    /**
115
     * Db::free()
116
     * @return void
117
     */
118
    public function free()
119
    {
120
        //			@mysql_free_result($this->queryId);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
121
        //			$this->queryId = 0;
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
122
    }
123
124
    /**
125
     * Db::query()
126
     *
127
     *  Sends an SQL query to the database
128
     *
129
     * @param mixed $queryString
130
     * @param string $line
131
     * @param string $file
132
     * @return mixed 0 if no query or query id handler, safe to ignore this return
133
     */
134 2
    public function query($queryString, $line = '', $file = '')
135
    {
136
        /* No empty queries, please, since PHP4 chokes on them. */
137
        /* The empty query string is passed on from the constructor,
138
        * when calling the class without a query, e.g. in situations
139
        * like these: '$db = new db_Subclass;'
140
        */
141 2
        if ($queryString == '') {
142
            return 0;
143
        }
144 2
        if (!$this->connect()) {
145
            return 0;
146
            /* we already complained in connect() about that. */
147
        }
148
        // New query, discard previous result.
149 2
        if ($this->queryId !== false) {
0 ignored issues
show
introduced by
The condition $this->queryId !== false is always true.
Loading history...
150 2
            $this->free();
151
        }
152
153 2
        if ($this->Debug) {
154
            printf("Debug: query = %s<br>\n", $queryString);
155
        }
156 2
        if (isset($GLOBALS['log_queries']) && $GLOBALS['log_queries'] !== false) {
157
            $this->log($queryString, $line, $file);
158
        }
159
160 2
        $this->queryId = $this->linkId->prepare($queryString);
161 2
        $success = $this->queryId->execute();
162 2
        $this->Rows = $this->queryId->fetchAll();
163
        //$this->log("PDO Query $queryString (S:$success) - ".count($this->Rows).' Rows', __LINE__, __FILE__);
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
164 2
        $this->Row = -1;
165 2
        if ($success === false) {
166
            $this->emailError($queryString, json_encode($this->queryId->errorInfo(), JSON_PRETTY_PRINT), $line, $file);
167
        }
168
169
        // Will return nada if it fails. That's fine.
170 2
        return $this->queryId;
171
    }
172
173
    /* public: walk result set */
174
175
    /**
176
     * Db::next_record()
177
     * @param mixed $resultType
178
     * @return bool
179
     */
180 2
    public function next_record($resultType = MYSQLI_ASSOC)
181
    {
182
        // PDO result types so far seem to be +1
183 2
        ++$resultType;
184 2
        if (!$this->queryId) {
185
            $this->halt('next_record called with no query pending.');
186
            return 0;
187
        }
188
189 2
        ++$this->Row;
190 2
        $this->Record = $this->Rows[$this->Row];
191
192 2
        $stat = is_array($this->Record);
193 2
        if (!$stat && $this->autoFree) {
194
            $this->free();
195
        }
196 2
        return $stat;
197
    }
198
199
    /* public: position in result set */
200
201
    /**
202
     * Db::seek()
203
     * @param integer $pos
204
     * @return int
205
     */
206
    public function seek($pos = 0)
207
    {
208
        if (isset($this->Rows[$pos])) {
209
            $this->Row = $pos;
210
        } else {
211
            $this->halt("seek($pos) failed: result has ".count($this->Rows).' rows');
212
            /* half assed attempt to save the day,
213
            * but do not consider this documented or even
214
            * desirable behaviour.
215
            */
216
            return 0;
217
        }
218
        return 1;
219
    }
220
221
    /**
222
     * Initiates a transaction
223
     * @return bool
224
     */
225
    public function transactionBegin()
226
    {
227
        return $this->linkId->beginTransaction();
228
    }
229
230
    /**
231
     * Commits a transaction
232
     * @return bool
233
     */
234
    public function transactionCommit()
235
    {
236
        return $this->linkId->commit();
237
    }
238
239
    /**
240
     * Rolls back a transaction
241
     * @return bool
242
     */
243
    public function transactionAbort()
244
    {
245
        return $this->linkId->rollBack();
246
    }
247
248
    /**
249
     * Db::getLastInsertId()
250
     * @param mixed $table
251
     * @param mixed $field
252
     * @return int
253
     */
254
    public function getLastInsertId($table, $field)
255
    {
256
        if (!isset($table) || $table == '' || !isset($field) || $field == '') {
257
            return -1;
258
        }
259
        return $this->linkId->lastInsertId();
260
    }
261
262
    /* public: table locking */
263
264
    /**
265
     * Db::lock()
266
     * @param mixed  $table
267
     * @param string $mode
268
     * @return void
269
     */
270
    public function lock($table, $mode = 'write')
0 ignored issues
show
Unused Code introduced by
The parameter $table is not used and could be removed. ( Ignorable by Annotation )

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

270
    public function lock(/** @scrutinizer ignore-unused */ $table, $mode = 'write')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $mode is not used and could be removed. ( Ignorable by Annotation )

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

270
    public function lock($table, /** @scrutinizer ignore-unused */ $mode = 'write')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
271
    {
272
        /*			$this->connect();
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
273
274
        * $query = "lock tables ";
275
        * if (is_array($table))
276
        * {
277
        * foreach ($table as $key => $value)
278
        * {
279
        * if ($key == "read" && $key!=0)
280
        * {
281
        * $query .= "$value read, ";
282
        * }
283
        * else
284
        * {
285
        * $query .= "$value $mode, ";
286
        * }
287
        * }
288
        * $query = mb_substr($query,0,-2);
289
        * }
290
        * else
291
        * {
292
        * $query .= "$table $mode";
293
        * }
294
        * $res = @mysql_query($query, $this->linkId);
295
        * if (!$res)
296
        * {
297
        * $this->halt("lock($table, $mode) failed.");
298
        * return 0;
299
        * }
300
        * return $res;
301
        */
302
    }
303
304
    /**
305
     * Db::unlock()
306
     * @return void
307
     */
308
    public function unlock()
309
    {
310
        /*			$this->connect();
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
311
312
        * $res = @mysql_query("unlock tables");
313
        * if (!$res)
314
        * {
315
        * $this->halt("unlock() failed.");
316
        * return 0;
317
        * }
318
        * return $res;
319
        */
320
    }
321
322
    /* public: evaluate the result (size, width) */
323
324
    /**
325
     * Db::affectedRows()
326
     *
327
     * @return mixed
328
     */
329
    public function affectedRows()
330
    {
331
        return @$this->queryId->rowCount();
0 ignored issues
show
Bug introduced by
The method rowCount() does not exist on integer. ( Ignorable by Annotation )

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

331
        return @$this->queryId->/** @scrutinizer ignore-call */ rowCount();

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...
332
    }
333
334
    /**
335
     * Db::num_rows()
336
     * @return int
337
     */
338
    public function num_rows()
339
    {
340
        return count($this->Rows);
341
    }
342
343
    /**
344
     * Db::num_fields()
345
     * @return int
346
     */
347
    public function num_fields()
348
    {
349
        $keys = array_keys($this->Rows);
350
        return count($this->Rows[$keys[0]]);
351
    }
352
353
    /**
354
     * @param mixed $msg
355
     * @param string $line
356
     * @param string $file
357
     * @return mixed|void
358
     */
359
    public function haltmsg($msg, $line = '', $file = '')
360
    {
361
        $this->log("Database error: $msg", $line, $file, 'error');
362
        if ($this->Errno != '0' || $this->Error != '()') {
363
            $this->log('PDO MySQL Error: '.json_encode($this->linkId->errorInfo()), $line, $file, 'error');
364
        }
365
        $this->logBackTrace($msg, $line, $file);
366
    }
367
368
    /**
369
     * Db::tableNames()
370
     *
371
     * @return array
372
     */
373
    public function tableNames()
374
    {
375
        $return = [];
376
        $this->query('SHOW TABLES');
377
        foreach ($this->Rows as $i => $info) {
378
            $return[$i]['table_name'] = $info[0];
379
            $return[$i]['tablespace_name'] = $this->database;
380
            $return[$i]['database'] = $this->database;
381
        }
382
        return $return;
383
    }
384
}
385