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

MySqliDriver::setCharset()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.3332

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 4
nop 3
dl 0
loc 9
ccs 4
cts 6
cp 0.6667
crap 3.3332
rs 9.6666
c 0
b 0
f 0
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 40
    public function __construct(array $config = [])
27
    {
28 40
        $driver = new mysqli_driver();
29 40
        $driver->report_mode = MYSQLI_REPORT_STRICT | MYSQLI_REPORT_ERROR;
30
31 40
        $this->config = $config;
32 40
    }
33
34
    /**
35
     * @return mixed
36
     * @throws Exceptions\Exception
37
     */
38 20
    public function getConnect()
39
    {
40 20
        if (! $this->isConnected()) {
41 1
            return $this->connect();
42
        }
43
44 20
        return $this->conn;
45
    }
46
47
    /**
48
     * @return mysqli
49
     * @throws Exceptions\Exception
50
     */
51 21
    public function connect() : mysqli
52
    {
53
        try {
54 21
            $this->conn = new mysqli(
55 21
                $this->config['host'],
56 21
                $this->config['user'],
57 21
                $this->config['pass'],
58 21
                $this->config['base']
59
            );
60
61 20
            if ($this->isConnected() && $this->getConnect()->connect_error) {
62
                throw new Exceptions\ConnectException($this->conn->connect_error);
63
            }
64
65 20
            if (! $this->isConnected()) {
66
                throw new Exceptions\ConnectException(
67 20
                    $this->getLastError() ?: 'Failed to create the database connection!'
68
                );
69
            }
70 1
        } catch (mysqli_sql_exception $exception) {
71 1
            throw new Exceptions\ConnectException($exception->getMessage(), $exception->getCode());
72
        }
73
74 20
        return $this->conn;
75
    }
76
77
    /**
78
     * {@inheritDoc}
79
     */
80 1
    public function disconnect() : DriverInterface
81
    {
82 1
        if ($this->isConnected()) {
83 1
            $this->conn->close();
84
        }
85
86 1
        $this->conn = null;
87
88 1
        return $this;
89
    }
90
91
    /**
92
     * @return bool
93
     */
94 20
    public function isConnected() : bool
95
    {
96 20
        return ($this->conn instanceof mysqli);
97
    }
98
99
    /**
100
     * @param $data
101
     * @return mixed
102
     * @throws Exceptions\Exception
103
     */
104 1
    public function escape($data)
105
    {
106 1
        return $this->getConnect()->escape_string($data);
107
    }
108
109
    /**
110
     * @return mixed
111
     * @throws Exceptions\Exception
112
     */
113 3
    public function getInsertId()
114
    {
115 3
        return $this->getConnect()->insert_id;
116
    }
117
118
    /**
119
     * @return int
120
     * @throws Exceptions\Exception
121
     */
122 8
    public function getAffectedRows() : int
123
    {
124 8
        return $this->getConnect()->affected_rows;
125
    }
126
127
    /**
128
     * @return string
129
     * @throws Exceptions\Exception
130
     */
131 1
    public function getVersion() : string
132
    {
133 1
        return $this->getConnect()->server_info;
134
    }
135
136
    /**
137
     * @param mysqli_result $result
138
     * @return int
139
     */
140 10
    public function getRecordCount($result) : int
141
    {
142 10
        return $result->num_rows;
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     */
148 20
    public function setCharset(string $charset, string $collation, $method = null) : bool
149
    {
150 20
        if ($method === null) {
151
            $method = $this->config['method'];
152
        }
153 20
        if ($this->query($method . ' ' . $charset . ' COLLATE ' . $collation) === true) {
154 20
            return $this->getConnect()->set_charset($charset);
155
        }
156
        return false;
157
    }
158
159
    /**
160
     * @param $result
161
     * @return bool
162
     */
163 14
    public function isResult($result) : bool
164
    {
165 14
        return $result instanceof mysqli_result;
166
    }
167
168
    /**
169
     * @param mysqli_result $result
170
     * @return int
171
     */
172 1
    public function numFields($result) : int
173
    {
174 1
        return $result->field_count;
175
    }
176
177
    /**
178
     * @param mysqli_result $result
179
     * @param int $col
180
     * @return string|null
181
     */
182 1
    public function fieldName($result, $col = 0) :? string
183
    {
184 1
        $field = $result->fetch_field_direct($col);
185
186 1
        return $field->name ?? null;
187
    }
188
189
    /**
190
     * @param string $name
191
     * @return bool
192
     * @throws Exceptions\Exception
193
     */
194
    public function selectDb(string $name) : bool
195
    {
196
        return $this->getConnect()->select_db($name);
197
    }
198
199
    /**
200
     * @param mysqli_result $result
201
     * @param string $mode
202
     * @return array|mixed|object|\stdClass
203
     * @throws Exceptions\Exception
204
     */
205 8
    public function getRow($result, $mode = 'assoc')
206
    {
207
        switch ($mode) {
208 8
            case 'assoc':
209 6
                $out = $result->fetch_assoc();
210 6
                break;
211 4
            case 'num':
212 4
                $out = $result->fetch_row();
213 4
                break;
214 1
            case 'object':
215 1
                $out = $result->fetch_object();
216 1
                break;
217 1
            case 'both':
218 1
                $out = $result->fetch_array(MYSQLI_BOTH);
219 1
                break;
220
            default:
221
                throw new Exceptions\UnknownFetchTypeException(
222
                    "Unknown get type ($mode) specified for fetchRow - must be empty, 'assoc', 'num' or 'both'."
223
                );
224
        }
225
226 8
        return $out;
227
    }
228
229
    /**
230
     * @param string $query
231
     * @return mixed
232
     * @throws Exceptions\Exception
233
     */
234 20
    public function query(string $query)
235
    {
236
        try {
237 20
            $result = $this->getConnect()->query($query);
238 2
        } catch (mysqli_sql_exception $exception) {
239 2
            $reflect = new ReflectionClass($exception);
240 2
            $property = $reflect->getProperty('sqlstate');
241 2
            $property->setAccessible(true);
242 2
            throw (new Exceptions\QueryException($exception->getMessage(), $property->getValue($exception)))
243 2
                ->setQuery($query);
244
        }
245
246 20
        return $result;
247
    }
248
249
    /**
250
     * @param string $name
251
     * @param $result
252
     * @return array
253
     * @throws Exceptions\Exception
254
     */
255 3
    public function getColumn(string $name, $result) : array
256
    {
257 3
        $col = [];
258
259 3
        if ($result instanceof mysqli_result) {
260 3
            while ($row = $this->getRow($result)) {
261 3
                $col[] = $row[$name];
262
            }
263
        }
264
265 3
        return $col;
266
    }
267
268
    /**
269
     * @param $result
270
     * @return array
271
     */
272 1
    public function getColumnNames($result) : array
273
    {
274 1
        $names = [];
275
276 1
        if ($result instanceof mysqli_result) {
277 1
            $limit = $this->numFields($result);
278 1
            for ($i = 0; $i < $limit; $i++) {
279 1
                $names[] = $this->fieldName($result, $i);
280
            }
281
        }
282
283 1
        return $names;
284
    }
285
286
    /**
287
     * @param $result
288
     * @return bool|mixed
289
     * @throws Exceptions\Exception
290
     */
291 3
    public function getValue($result)
292
    {
293 3
        $out = false;
294
295 3
        if ($result instanceof mysqli_result) {
296 3
            $result = $this->getRow($result, 'num');
297 3
            $out = $result[0] ?? false;
298
        }
299
300 3
        return $out;
301
    }
302
303
    /**
304
     * @param $result
305
     * @return array|mixed
306
     * @throws Exceptions\Exception
307
     */
308 1
    public function getTableMetaData($result)
309
    {
310 1
        $out = [];
311
312 1
        if ($result instanceof mysqli_result) {
313 1
            while ($row = $this->getRow($result)) {
314 1
                $fieldName = $row['Field'];
315 1
                $out[$fieldName] = $row;
316
            }
317
        }
318
319 1
        return $out;
320
    }
321
322
    /**
323
     * @return string|null
324
     * @throws Exceptions\Exception
325
     */
326 1
    public function getLastError() :? string
327
    {
328 1
        return $this->getConnect()->error;
329
    }
330
331
    /**
332
     * @return string|null
333
     * @throws Exceptions\Exception
334
     */
335 1
    public function getLastErrorNo() :? string
336
    {
337 1
        return (string)$this->getConnect()->errno;
338
    }
339
340
    /**
341
     * {@inheritDoc}
342
     */
343 1
    public function dataSeek(&$result, $position) : bool
344
    {
345 1
        return $result->data_seek($position);
346
    }
347
}
348