Passed
Push — master ( 35c865...a45e07 )
by Agel_Nash
03:00
created

MySqliDriver   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 345
Duplicated Lines 0 %

Test Coverage

Coverage 93.04%

Importance

Changes 0
Metric Value
wmc 53
dl 0
loc 345
ccs 107
cts 115
cp 0.9304
rs 7.4757
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B connect() 0 24 6
A escape() 0 3 1
B getRow() 0 22 5
A query() 0 13 2
A disconnect() 0 9 2
A getAffectedRows() 0 3 1
A isConnected() 0 3 1
A getVersion() 0 3 1
A setCharset() 0 9 3
A getConfig() 0 3 1
A selectDb() 0 3 1
A getConnect() 0 7 2
A getInsertId() 0 3 1
A isResult() 0 3 1
A getTableMetaData() 0 12 3
A dataSeek() 0 3 2
A getLastError() 0 3 1
A numFields() 0 3 2
A getRecordCount() 0 3 2
A fieldName() 0 5 3
A getColumnNames() 0 12 3
A getColumn() 0 13 4
A getValue() 0 10 3
A getLastErrorNo() 0 3 1

How to fix   Complexity   

Complex Class

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

1
<?php namespace AgelxNash\Modx\Evo\Database\Drivers;
2
3
use AgelxNash\Modx\Evo\Database\Interfaces\DriverInterface;
4
use AgelxNash\Modx\Evo\Database\Exceptions;
5
use mysqli;
6
use mysqli_result;
7
use mysqli_sql_exception;
8
use mysqli_driver;
9
use ReflectionClass;
10
11
class MySqliDriver implements DriverInterface
12
{
13
    /**
14
     * @var mysqli
15
     */
16
    protected $conn;
17
18
    /**
19
     * @var array
20
     */
21
    protected $config;
22
23
    /**
24
     * {@inheritDoc}
25
     */
26 44
    public function __construct(array $config = [])
27
    {
28 44
        $driver = new mysqli_driver();
29 44
        $driver->report_mode = MYSQLI_REPORT_STRICT | MYSQLI_REPORT_ERROR;
30
31 44
        $this->config = $config;
32 44
    }
33
34
    /**
35
     * @return array
36
     */
37 1
    public function getConfig()
38
    {
39 1
        return $this->config;
40
    }
41
42
    /**
43
     * @return mixed
44
     * @throws Exceptions\Exception
45
     */
46 24
    public function getConnect()
47
    {
48 24
        if (! $this->isConnected()) {
49 24
            return $this->connect();
50
        }
51
52 23
        return $this->conn;
53
    }
54
55
    /**
56
     * @return mysqli
57
     * @throws Exceptions\Exception
58
     */
59 24
    public function connect()
60
    {
61
        try {
62 24
            $this->conn = new mysqli(
63 24
                $this->config['host'],
64 24
                $this->config['username'],
65 24
                $this->config['password'],
66 24
                $this->config['database']
67
            );
68
69 23
            if ($this->isConnected() && $this->getConnect()->connect_error) {
70
                throw new Exceptions\ConnectException($this->conn->connect_error);
71
            }
72
73 23
            if (! $this->isConnected()) {
74
                throw new Exceptions\ConnectException(
75 23
                    $this->getLastError() ?: 'Failed to create the database connection!'
76
                );
77
            }
78 1
        } catch (mysqli_sql_exception $exception) {
79 1
            throw new Exceptions\ConnectException($exception->getMessage(), $exception->getCode());
80
        }
81
82 23
        return $this->conn;
83
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88 1
    public function disconnect()
89
    {
90 1
        if ($this->isConnected()) {
91 1
            $this->conn->close();
92
        }
93
94 1
        $this->conn = null;
95
96 1
        return $this;
97
    }
98
99
    /**
100
     * @return bool
101
     */
102 24
    public function isConnected()
103
    {
104 24
        return ($this->conn instanceof mysqli);
105
    }
106
107
    /**
108
     * @param $data
109
     * @return mixed
110
     * @throws Exceptions\Exception
111
     */
112 1
    public function escape($data)
113
    {
114 1
        return $this->getConnect()->escape_string($data);
115
    }
116
117
    /**
118
     * @return mixed
119
     * @throws Exceptions\Exception
120
     */
121 3
    public function getInsertId()
122
    {
123 3
        return $this->getConnect()->insert_id;
124
    }
125
126
    /**
127
     * @return int
128
     * @throws Exceptions\Exception
129
     */
130 8
    public function getAffectedRows()
131
    {
132 8
        return $this->getConnect()->affected_rows;
133
    }
134
135
    /**
136
     * @return string
137
     * @throws Exceptions\Exception
138
     */
139 2
    public function getVersion()
140
    {
141 2
        return $this->getConnect()->server_info;
142
    }
143
144
    /**
145
     * @param mysqli_result $result
146
     * @return int
147
     */
148 11
    public function getRecordCount($result)
149
    {
150 11
        return $this->isResult($result) ? $result->num_rows : 0;
151
    }
152
153
    /**
154
     * {@inheritDoc}
155
     */
156 22
    public function setCharset($charset, $collation, $method = null)
157
    {
158 22
        if ($method === null) {
159
            $method = $this->config['method'];
160
        }
161 22
        if ($this->query($method . ' ' . $charset . ' COLLATE ' . $collation) === true) {
162 22
            return $this->getConnect()->set_charset($charset);
163
        }
164
        return false;
165
    }
166
167
    /**
168
     * @param $result
169
     * @return bool
170
     */
171 17
    public function isResult($result)
172
    {
173 17
        return $result instanceof mysqli_result;
174
    }
175
176
    /**
177
     * @param mysqli_result $result
178
     * @return int
179
     */
180 1
    public function numFields($result)
181
    {
182 1
        return $this->isResult($result) ? $result->field_count : 0;
183
    }
184
185
    /**
186
     * @param mysqli_result $result
187
     * @param int $col
188
     * @return string|null
189
     */
190 1
    public function fieldName($result, $col = 0)
191
    {
192 1
        $field = $this->isResult($result) ? $result->fetch_field_direct($col) : [];
193
194 1
        return isset($field->name) ? $field->name : null;
195
    }
196
197
    /**
198
     * @param string $name
199
     * @return bool
200
     * @throws Exceptions\Exception
201
     */
202
    public function selectDb($name)
203
    {
204
        return $this->getConnect()->select_db($name);
205
    }
206
207
    /**
208
     * @param mysqli_result $result
209
     * @param string $mode
210
     * @return array|mixed|object|\stdClass
211
     * @throws Exceptions\Exception
212
     */
213 8
    public function getRow($result, $mode = 'assoc')
214
    {
215
        switch ($mode) {
216 8
            case 'assoc':
217 6
                $out = $result->fetch_assoc();
218 6
                break;
219 4
            case 'num':
220 4
                $out = $result->fetch_row();
221 4
                break;
222 1
            case 'object':
223 1
                $out = $result->fetch_object();
224 1
                break;
225 1
            case 'both':
226 1
                $out = $result->fetch_array(MYSQLI_BOTH);
227 1
                break;
228
            default:
229
                throw new Exceptions\UnknownFetchTypeException(
230
                    "Unknown get type ($mode) specified for fetchRow - must be empty, 'assoc', 'num' or 'both'."
231
                );
232
        }
233
234 8
        return $out;
235
    }
236
237
    /**
238
     * @param string $query
239
     * @return mixed
240
     * @throws Exceptions\Exception
241
     */
242 22
    public function query($query)
243
    {
244
        try {
245 22
            $result = $this->getConnect()->query($query);
246 2
        } catch (mysqli_sql_exception $exception) {
247 2
            $reflect = new ReflectionClass($exception);
248 2
            $property = $reflect->getProperty('sqlstate');
249 2
            $property->setAccessible(true);
250 2
            throw (new Exceptions\QueryException($exception->getMessage(), $property->getValue($exception)))
251 2
                ->setQuery($query);
252
        }
253
254 22
        return $result;
255
    }
256
257
    /**
258
     * @param string $name
259
     * @param $result
260
     * @return array
261
     * @throws Exceptions\Exception
262
     */
263 3
    public function getColumn($name, $result)
264
    {
265 3
        $col = [];
266
267 3
        if ($this->isResult($result)) {
268 3
            while ($row = $this->getRow($result)) {
269 3
                if (array_key_exists($name, $row)) {
0 ignored issues
show
Bug introduced by
It seems like $row can also be of type object and stdClass; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

269
                if (array_key_exists($name, /** @scrutinizer ignore-type */ $row)) {
Loading history...
270 3
                    $col[] = $row[$name];
271
                }
272
            }
273
        }
274
275 3
        return $col;
276
    }
277
278
    /**
279
     * @param $result
280
     * @return array
281
     */
282 1
    public function getColumnNames($result)
283
    {
284 1
        $names = [];
285
286 1
        if ($this->isResult($result)) {
287 1
            $limit = $this->numFields($result);
288 1
            for ($i = 0; $i < $limit; $i++) {
289 1
                $names[] = $this->fieldName($result, $i);
290
            }
291
        }
292
293 1
        return $names;
294
    }
295
296
    /**
297
     * @param $result
298
     * @return bool|mixed
299
     * @throws Exceptions\Exception
300
     */
301 3
    public function getValue($result)
302
    {
303 3
        $out = false;
304
305 3
        if ($this->isResult($result)) {
306 3
            $result = $this->getRow($result, 'num');
307 3
            $out = isset($result[0]) ? $result[0] : false;
308
        }
309
310 3
        return $out;
311
    }
312
313
    /**
314
     * @param $result
315
     * @return array|mixed
316
     * @throws Exceptions\Exception
317
     */
318 1
    public function getTableMetaData($result)
319
    {
320 1
        $out = [];
321
322 1
        if ($this->isResult($result)) {
323 1
            while ($row = $this->getRow($result)) {
324 1
                $fieldName = $row['Field'];
325 1
                $out[$fieldName] = $row;
326
            }
327
        }
328
329 1
        return $out;
330
    }
331
332
    /**
333
     * @return string|null
334
     * @throws Exceptions\Exception
335
     */
336 1
    public function getLastError()
337
    {
338 1
        return $this->getConnect()->error;
339
    }
340
341
    /**
342
     * @return string|null
343
     * @throws Exceptions\Exception
344
     */
345 1
    public function getLastErrorNo()
346
    {
347 1
        return (string)$this->getConnect()->sqlstate;
348
    }
349
350
    /**
351
     * {@inheritDoc}
352
     */
353 1
    public function dataSeek(&$result, $position)
354
    {
355 1
        return $this->isResult($result) ? $result->data_seek($position) : false;
356
    }
357
}
358