Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
73.97% |
162 / 219 |
|
60.53% |
23 / 38 |
CRAP | |
0.00% |
0 / 1 |
Pdo | |
73.97% |
162 / 219 |
|
60.53% |
23 / 38 |
333.17 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
connect | |
76.92% |
10 / 13 |
|
0.00% |
0 / 1 |
10.00 | |||
setOptions | |
85.71% |
12 / 14 |
|
0.00% |
0 / 1 |
6.10 | |||
hasOptions | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
6 | |||
dbFileExists | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getDsn | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
beginTransaction | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
commit | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
rollback | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
inTransaction | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isSuccess | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
3 | |||
setAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAttribute | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
query | |
66.67% |
14 / 21 |
|
0.00% |
0 / 1 |
8.81 | |||
prepare | |
92.31% |
12 / 13 |
|
0.00% |
0 / 1 |
7.02 | |||
bindParams | |
68.18% |
15 / 22 |
|
0.00% |
0 / 1 |
13.22 | |||
bindParam | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
bindValue | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
bindColumn | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
46.67% |
7 / 15 |
|
0.00% |
0 / 1 |
11.46 | |||
fetch | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
5.02 | |||
fetchAll | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
escape | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLastId | |
75.00% |
9 / 12 |
|
0.00% |
0 / 1 |
5.39 | |||
getNumberOfRows | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
3.03 | |||
getNumberOfAffectedRows | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getVersion | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getTables | |
94.12% |
16 / 17 |
|
0.00% |
0 / 1 |
7.01 | |||
getErrorMessage | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
buildError | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getNumberOfFields | |
71.43% |
5 / 7 |
|
0.00% |
0 / 1 |
3.21 | |||
closeCursor | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCountOfFields | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
fetchColumn | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCountOfRows | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
debugDumpParams | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
exec | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Db\Adapter; |
15 | |
16 | /** |
17 | * PDO database adapter class |
18 | * |
19 | * @category Pop |
20 | * @package Pop\Db |
21 | * @author Nick Sagona, III <dev@nolainteractive.com> |
22 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
23 | * @license http://www.popphp.org/license New BSD License |
24 | * @version 6.5.0 |
25 | */ |
26 | class Pdo extends AbstractAdapter |
27 | { |
28 | |
29 | /** |
30 | * PDO DSN |
31 | * @var ?string |
32 | */ |
33 | protected ?string $dsn = null; |
34 | |
35 | /** |
36 | * PDO type |
37 | * @var ?string |
38 | */ |
39 | protected ?string $type = null; |
40 | |
41 | /** |
42 | * Statement placeholder |
43 | * @var ?string |
44 | */ |
45 | protected ?string $placeholder = null; |
46 | |
47 | /** |
48 | * Statement result |
49 | * @var bool |
50 | */ |
51 | protected bool $statementResult = false; |
52 | |
53 | /** |
54 | * Constructor |
55 | * |
56 | * Instantiate the database connection object using PDO |
57 | * |
58 | * @param array $options |
59 | */ |
60 | public function __construct(array $options = []) |
61 | { |
62 | if (!empty($options)) { |
63 | $this->connect($options); |
64 | } |
65 | } |
66 | |
67 | /** |
68 | * Connect to the database |
69 | * |
70 | * @param array $options |
71 | * @return Pdo |
72 | */ |
73 | public function connect(array $options = []): Pdo |
74 | { |
75 | if (!empty($options)) { |
76 | $this->setOptions($options); |
77 | } else if (!$this->hasOptions()) { |
78 | $this->throwError('Error: The proper database credentials were not passed.'); |
79 | } |
80 | |
81 | try { |
82 | if ($this->type == 'sqlite') { |
83 | $this->connection = (isset($this->options['options']) && is_array($this->options['options'])) ? |
84 | new \PDO($this->dsn, null, null, $this->options['options']) : new \PDO($this->dsn); |
85 | } else { |
86 | $this->connection = (isset($this->options['options']) && is_array($this->options['options'])) ? |
87 | new \PDO($this->dsn, $this->options['username'], $this->options['password'], $this->options['options']) : |
88 | new \PDO($this->dsn, $this->options['username'], $this->options['password']); |
89 | } |
90 | } catch (\PDOException $e) { |
91 | $this->throwError('PDO Connection Error: ' . $e->getMessage() . ' (#' . $e->getCode() . ')'); |
92 | } |
93 | |
94 | return $this; |
95 | } |
96 | |
97 | /** |
98 | * Set database connection options |
99 | * |
100 | * @param array $options |
101 | * @return Pdo |
102 | */ |
103 | public function setOptions(array $options): Pdo |
104 | { |
105 | if (!isset($options['host'])) { |
106 | $options['host'] = 'localhost'; |
107 | } |
108 | |
109 | $this->options = $options; |
110 | |
111 | if (!$this->hasOptions()) { |
112 | $this->throwError('Error: The proper database credentials were not passed.'); |
113 | } |
114 | |
115 | $this->type = strtolower($this->options['type']); |
116 | |
117 | if ($this->type == 'sqlite') { |
118 | if (!$this->dbFileExists()) { |
119 | $this->throwError("Error: The database file '" . $this->options['database'] . "'does not exists."); |
120 | } |
121 | $this->dsn = $this->type . ':' . $this->options['database']; |
122 | } else { |
123 | $this->dsn = ($this->type == 'sqlsrv') ? |
124 | $this->type . ':Server=' . $this->options['host'] . ';Database=' . $this->options['database'] : |
125 | $this->type . ':host=' . $this->options['host'] . ';dbname=' . $this->options['database']; |
126 | } |
127 | |
128 | return $this; |
129 | } |
130 | |
131 | /** |
132 | * Has database connection options |
133 | * |
134 | * @return bool |
135 | */ |
136 | public function hasOptions(): bool |
137 | { |
138 | if (!isset($this->options['type'])) { |
139 | return false; |
140 | } else { |
141 | return (strtolower($this->options['type']) == 'sqlite') ? |
142 | (isset($this->options['database'])) : |
143 | (isset($this->options['database']) && isset($this->options['host']) && |
144 | isset($this->options['username']) && isset($this->options['password'])); |
145 | } |
146 | } |
147 | |
148 | /** |
149 | * Does the database file exist |
150 | * |
151 | * @return bool |
152 | */ |
153 | public function dbFileExists(): bool |
154 | { |
155 | return (isset($this->options['database']) && file_exists($this->options['database'])); |
156 | } |
157 | |
158 | /** |
159 | * Return the DSN |
160 | * |
161 | * @return ?string |
162 | */ |
163 | public function getDsn(): ?string |
164 | { |
165 | return $this->dsn; |
166 | } |
167 | |
168 | /** |
169 | * Return the type |
170 | * |
171 | * @return ?string |
172 | */ |
173 | public function getType(): ?string |
174 | { |
175 | return $this->type; |
176 | } |
177 | |
178 | /** |
179 | * Begin a transaction |
180 | * |
181 | * @return Pdo |
182 | */ |
183 | public function beginTransaction(): Pdo |
184 | { |
185 | $this->getTransactionManager()->enter( |
186 | beginFunc: function () { $this->connection->beginTransaction(); }, |
187 | savepointFunc: function (string $sp) { $this->query('SAVEPOINT ' . $sp); }, |
188 | ); |
189 | |
190 | return $this; |
191 | } |
192 | |
193 | /** |
194 | * Commit a transaction |
195 | * |
196 | * @return Pdo |
197 | */ |
198 | public function commit(): Pdo |
199 | { |
200 | $this->getTransactionManager()->leave(true, |
201 | commitFunc: function () { $this->connection->commit(); }, |
202 | rollbackFunc: function () { $this->connection->rollBack(); }, |
203 | savepointReleaseFunc: function (string $sp) { $this->query('RELEASE SAVEPOINT ' . $sp); }, |
204 | ); |
205 | return $this; |
206 | } |
207 | |
208 | /** |
209 | * Rollback a transaction |
210 | * |
211 | * @return Pdo |
212 | */ |
213 | public function rollback(): Pdo |
214 | { |
215 | $this->getTransactionManager()->leave(false, |
216 | rollbackFunc: function () { $this->connection->rollBack(); }, |
217 | savepointRollbackFunc: function (string $sp) { $this->query('ROLLBACK TO SAVEPOINT ' . $sp); }, |
218 | ); |
219 | |
220 | return $this; |
221 | } |
222 | |
223 | /** |
224 | * Method checks, whether the transaction is initiated. |
225 | * |
226 | * @return bool |
227 | */ |
228 | public function inTransaction(): bool |
229 | { |
230 | return $this->connection->inTransaction(); |
231 | } |
232 | |
233 | /** |
234 | * Check if transaction is success |
235 | * |
236 | * @return bool |
237 | */ |
238 | public function isSuccess(): bool |
239 | { |
240 | return ((($this->result) || ($this->statementResult)) && (!$this->hasError())); |
241 | } |
242 | |
243 | /** |
244 | * Method sets the value of the request attribute PDO. |
245 | * |
246 | * @param int $attribute A request attribute |
247 | * @param mixed $value The value of the attribute request |
248 | * @return bool |
249 | */ |
250 | public function setAttribute(int $attribute, mixed $value): bool |
251 | { |
252 | return $this->connection->setAttribute($attribute, $value); |
253 | } |
254 | |
255 | /** |
256 | * The method of obtaining the value of the request attribute PDO. |
257 | * |
258 | * @param int $attribute A request attribute |
259 | * @return string |
260 | */ |
261 | public function getAttribute(int $attribute): string |
262 | { |
263 | return $this->connection->getAttribute($attribute); |
264 | } |
265 | |
266 | /** |
267 | * Execute a SQL query directly |
268 | * |
269 | * @param mixed $sql |
270 | * @return Pdo |
271 | */ |
272 | public function query(mixed $sql): Pdo |
273 | { |
274 | if ($sql instanceof \Pop\Db\Sql\AbstractSql) { |
275 | $sql = (string)$sql; |
276 | } |
277 | |
278 | $this->statement = null; |
279 | $this->statementResult = false; |
280 | |
281 | $sth = $this->connection->prepare($sql); |
282 | |
283 | if (!($sth->execute())) { |
284 | if ($this->profiler !== null) { |
285 | $this->profiler->addStep(); |
286 | $this->profiler->current->setQuery($sql); |
287 | $this->profiler->current->addError($this->getErrorMessage($sth->errorInfo()), $sth->errorCode()); |
288 | } |
289 | $this->buildError($sth->errorCode(), $sth->errorInfo()) |
290 | ->throwError(); |
291 | } else { |
292 | if ($this->profiler !== null) { |
293 | $this->profiler->addStep(); |
294 | $this->profiler->current->setQuery($sql); |
295 | } |
296 | $this->result = $sth; |
297 | } |
298 | |
299 | if ($this->profiler !== null) { |
300 | $this->profiler->current->finish(); |
301 | if ($this->profiler->hasDebugger()) { |
302 | $this->profiler->debugger()->save(); |
303 | } |
304 | } |
305 | |
306 | return $this; |
307 | } |
308 | |
309 | /** |
310 | * Prepare a SQL query |
311 | * |
312 | * @param mixed $sql |
313 | * @param ?array $attribs |
314 | * @return Pdo |
315 | */ |
316 | public function prepare(mixed $sql, ?array $attribs = null): Pdo |
317 | { |
318 | if ($sql instanceof \Pop\Db\Sql\AbstractSql) { |
319 | $sql = (string)$sql; |
320 | } |
321 | |
322 | if (str_contains($sql, '?')) { |
323 | $this->placeholder = '?'; |
324 | } else if (str_contains($sql, ':')) { |
325 | $this->placeholder = ':'; |
326 | } |
327 | |
328 | if ($this->profiler !== null) { |
329 | $this->profiler->addStep(); |
330 | $this->profiler->current->setQuery($sql); |
331 | } |
332 | |
333 | if (($attribs !== null) && is_array($attribs)) { |
334 | $this->statement = $this->connection->prepare($sql, $attribs); |
335 | } else { |
336 | $this->statement = $this->connection->prepare($sql); |
337 | } |
338 | |
339 | return $this; |
340 | } |
341 | |
342 | /** |
343 | * Bind parameters to a prepared SQL query |
344 | * |
345 | * @param array $params |
346 | * @return Pdo |
347 | */ |
348 | public function bindParams(array $params): Pdo |
349 | { |
350 | if ($this->profiler !== null) { |
351 | $this->profiler->current->addParams($params); |
352 | } |
353 | |
354 | if ($this->placeholder == '?') { |
355 | $i = 1; |
356 | foreach ($params as $dbColumnName => $dbColumnValue) { |
357 | if (is_array($dbColumnValue)) { |
358 | foreach ($dbColumnValue as $k => $dbColumnVal) { |
359 | ${$dbColumnName . ($k + 1)} = $dbColumnVal; |
360 | $this->statement->bindParam($i, ${$dbColumnName . ($k + 1)}); |
361 | $i++; |
362 | |
363 | } |
364 | } else { |
365 | ${$dbColumnName} = $dbColumnValue; |
366 | $this->statement->bindParam($i, ${$dbColumnName}); |
367 | $i++; |
368 | } |
369 | } |
370 | } else if ($this->placeholder == ':') { |
371 | foreach ($params as $dbColumnName => $dbColumnValue) { |
372 | if (is_array($dbColumnValue)) { |
373 | foreach ($dbColumnValue as $k => $dbColumnVal) { |
374 | ${$dbColumnName} = $dbColumnVal; |
375 | $this->statement->bindParam(':' . $dbColumnName . ($k + 1), ${$dbColumnName}); |
376 | } |
377 | } else { |
378 | ${$dbColumnName} = $dbColumnValue; |
379 | $this->statement->bindParam(':' . $dbColumnName, ${$dbColumnName}); |
380 | } |
381 | } |
382 | } |
383 | |
384 | return $this; |
385 | } |
386 | |
387 | /** |
388 | * Bind a parameter for a prepared SQL query |
389 | * |
390 | * @param mixed $param |
391 | * @param mixed $value |
392 | * @param int $dataType |
393 | * @param ?int $length |
394 | * @param mixed $options |
395 | * @return Pdo |
396 | */ |
397 | public function bindParam(mixed $param, mixed &$value, int $dataType = \PDO::PARAM_STR, ?int $length = null, mixed $options = null): Pdo |
398 | { |
399 | if ($this->profiler !== null) { |
400 | $this->profiler->current->addParam($param, $value); |
401 | } |
402 | $this->statement->bindParam($param, $value, $dataType, (int)$length, $options); |
403 | return $this; |
404 | } |
405 | |
406 | /** |
407 | * Bind a value for a prepared SQL query |
408 | * |
409 | * @param mixed $param |
410 | * @param mixed $value |
411 | * @param int $dataType |
412 | * @return Pdo |
413 | */ |
414 | public function bindValue(mixed $param, mixed $value, int $dataType = \PDO::PARAM_STR): Pdo |
415 | { |
416 | if ($this->profiler !== null) { |
417 | $this->profiler->current->addParam($param, $value); |
418 | } |
419 | $this->statement->bindValue($param, $value, $dataType); |
420 | return $this; |
421 | } |
422 | |
423 | /** |
424 | * Bind a column to a PHP variable. |
425 | * |
426 | * @param mixed $column Number of the column (1-indexed) or name of the column in the result set. |
427 | * @param mixed $param Name of the PHP variable to which the column will be bound. |
428 | * @param int $dataType Data type of the parameter, specified by the PDO::PARAM_* constants. |
429 | * @return Pdo |
430 | */ |
431 | public function bindColumn(mixed $column, mixed $param, int $dataType = \PDO::PARAM_STR): Pdo |
432 | { |
433 | $this->statement->bindColumn($column, $param, $dataType); |
434 | return $this; |
435 | } |
436 | |
437 | /** |
438 | * Execute a prepared SQL query |
439 | * |
440 | * @return Pdo |
441 | */ |
442 | public function execute(): Pdo |
443 | { |
444 | if ($this->statement === null) { |
445 | $this->throwError('Error: The database statement resource is not currently set.'); |
446 | } |
447 | |
448 | $this->statementResult = $this->statement->execute(); |
449 | |
450 | if ($this->statement->errorCode() != 0) { |
451 | if ($this->profiler !== null) { |
452 | $this->profiler->current->addError( |
453 | $this->getErrorMessage($this->statement->errorInfo()), $this->statement->errorCode() |
454 | ); |
455 | } |
456 | $this->buildError($this->statement->errorCode(), $this->statement->errorInfo()) |
457 | ->throwError(); |
458 | } |
459 | |
460 | if ($this->profiler !== null) { |
461 | $this->profiler->current->finish(); |
462 | if ($this->profiler->hasDebugger()) { |
463 | $this->profiler->debugger()->save(); |
464 | } |
465 | } |
466 | |
467 | return $this; |
468 | } |
469 | |
470 | /** |
471 | * Fetch and return a row from the result |
472 | * |
473 | * @param int $dataType Data type of the parameter, specified by the PDO::PARAM_* constants. |
474 | * @return mixed |
475 | */ |
476 | public function fetch(int $dataType = \PDO::FETCH_ASSOC): mixed |
477 | { |
478 | if (($this->statement !== null) && ($this->statementResult !== false)) { |
479 | return $this->statement->fetch($dataType); |
480 | } else { |
481 | if ($this->result === null) { |
482 | $this->throwError('Error: The database statement resource is not currently set.'); |
483 | } |
484 | return $this->result->fetch($dataType); |
485 | } |
486 | } |
487 | |
488 | /** |
489 | * Fetch and return all rows from the result |
490 | * |
491 | * @param int $dataType Data type of the parameter, specified by the PDO::PARAM_* constants. |
492 | * @return array |
493 | */ |
494 | public function fetchAll(int $dataType = \PDO::FETCH_ASSOC): array |
495 | { |
496 | return $this->statement->fetchAll($dataType); |
497 | } |
498 | |
499 | /** |
500 | * Escape the value |
501 | * |
502 | * @param ?string $value |
503 | * @return string |
504 | */ |
505 | public function escape(?string $value = null): string |
506 | { |
507 | return substr($this->connection->quote($value), 1, -1); |
508 | } |
509 | |
510 | /** |
511 | * Return the last ID of the last query |
512 | * |
513 | * @return int |
514 | */ |
515 | public function getLastId(): int |
516 | { |
517 | $id = 0; |
518 | |
519 | // If pgsql |
520 | if ($this->type == 'pgsql') { |
521 | $this->query("SELECT lastval();"); |
522 | if ($this->result !== null) { |
523 | $insertRow = $this->result->fetch(); |
524 | $id = $insertRow[0]; |
525 | } |
526 | // Else, if sqlsrv |
527 | } else if ($this->type == 'sqlsrv') { |
528 | $this->query('SELECT SCOPE_IDENTITY() as Current_Identity'); |
529 | $row = $this->fetch(); |
530 | $id = (isset($row['Current_Identity'])) ? $row['Current_Identity'] : 0; |
531 | // Else, just get the last insert ID |
532 | } else { |
533 | $id = $this->connection->lastInsertId(); |
534 | } |
535 | |
536 | return $id; |
537 | } |
538 | |
539 | /** |
540 | * Return the number of rows from the last query |
541 | * |
542 | * @throws Exception |
543 | * @return int |
544 | */ |
545 | public function getNumberOfRows(): int |
546 | { |
547 | $count = 0; |
548 | |
549 | if ($this->result !== null) { |
550 | $count = $this->result->rowCount(); |
551 | } else if ($this->statement !== null) { |
552 | $count = $this->statement->rowCount(); |
553 | } else { |
554 | $this->throwError('Error: The database statement resource is not currently set.'); |
555 | } |
556 | |
557 | return $count; |
558 | } |
559 | |
560 | /** |
561 | * Return the number of affected rows from the last query |
562 | * |
563 | * @throws Exception |
564 | * @return int |
565 | */ |
566 | public function getNumberOfAffectedRows(): int |
567 | { |
568 | return $this->getNumberOfRows(); |
569 | } |
570 | |
571 | /** |
572 | * Return the database version |
573 | * |
574 | * @return string |
575 | */ |
576 | public function getVersion(): string |
577 | { |
578 | return 'PDO ' . substr($this->dsn, 0, strpos($this->dsn, ':')) . ' ' . |
579 | $this->connection->getAttribute(\PDO::ATTR_SERVER_VERSION); |
580 | } |
581 | |
582 | /** |
583 | * Return the tables in the database |
584 | * |
585 | * @return array |
586 | */ |
587 | public function getTables(): array |
588 | { |
589 | $tables = []; |
590 | |
591 | if (stripos($this->dsn, 'sqlite') !== false) { |
592 | $sql = "SELECT name FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' " . |
593 | "UNION ALL SELECT name FROM sqlite_temp_master WHERE type IN ('table', 'view') ORDER BY 1"; |
594 | |
595 | $this->query($sql); |
596 | while (($row = $this->fetch())) { |
597 | $tables[] = $row['name']; |
598 | } |
599 | } else { |
600 | if (stripos($this->dsn, 'pgsql') !== false) { |
601 | $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; |
602 | } else if (stripos($this->dsn, 'sqlsrv') !== false) { |
603 | $sql = "SELECT name FROM " . $this->database . ".sysobjects WHERE xtype = 'U'"; |
604 | } else { |
605 | $sql = 'SHOW TABLES'; |
606 | } |
607 | $this->query($sql); |
608 | while (($row = $this->fetch())) { |
609 | foreach($row as $value) { |
610 | $tables[] = $value; |
611 | } |
612 | } |
613 | } |
614 | |
615 | return $tables; |
616 | } |
617 | |
618 | /** |
619 | * Get the error message |
620 | * |
621 | * @param mixed $errorInfo |
622 | * @return ?string |
623 | */ |
624 | protected function getErrorMessage(mixed $errorInfo): ?string |
625 | { |
626 | if (is_array($errorInfo)) { |
627 | $errorMessage = null; |
628 | if (isset($errorInfo[1])) { |
629 | $errorMessage .= $errorInfo[1]; |
630 | } |
631 | if (isset($errorInfo[2])) { |
632 | $errorMessage .= ' : ' . $errorInfo[2]; |
633 | } |
634 | } else { |
635 | $errorMessage = $errorInfo; |
636 | } |
637 | |
638 | return $errorMessage; |
639 | } |
640 | |
641 | /** |
642 | * Build the error |
643 | * |
644 | * @param ?string $code |
645 | * @param ?array $info |
646 | * @return Pdo |
647 | */ |
648 | protected function buildError(?string $code = null, ?array $info = null): Pdo |
649 | { |
650 | if (($code === null) && ($info === null)) { |
651 | $errorCode = $this->connection->errorCode(); |
652 | $errorInfo = $this->connection->errorInfo(); |
653 | } else { |
654 | $errorCode = $code; |
655 | $errorInfo = $info; |
656 | } |
657 | |
658 | $this->setError('Error: ' . $errorCode . ' => ' . $this->getErrorMessage($errorInfo)); |
659 | return $this; |
660 | } |
661 | |
662 | /** |
663 | * Return the number of fields in the result. |
664 | * |
665 | * @throws Exception |
666 | * @return int |
667 | */ |
668 | public function getNumberOfFields(): int |
669 | { |
670 | $count = 0; |
671 | |
672 | if ($this->result !== null) { |
673 | $count = $this->result->columnCount(); |
674 | } else if ($this->statement !== null) { |
675 | $count = $this->statement->columnCount(); |
676 | } else { |
677 | $this->throwError('Error: The database statement resource is not currently set.'); |
678 | } |
679 | |
680 | return $count; |
681 | } |
682 | |
683 | /** |
684 | * Method closes the cursor, translating the request in the ready state. |
685 | * |
686 | * @return bool |
687 | */ |
688 | public function closeCursor(): bool |
689 | { |
690 | return $this->statement->closeCursor(); |
691 | } |
692 | |
693 | /** |
694 | * The method returns the number of columns in the result set. |
695 | * |
696 | * @return int |
697 | */ |
698 | public function getCountOfFields(): int |
699 | { |
700 | return $this->statement->columnCount(); |
701 | } |
702 | |
703 | /** |
704 | * The method receives data of one column from the next row of the result set. |
705 | * |
706 | * @param int $num The number of the table column |
707 | * @return mixed |
708 | */ |
709 | public function fetchColumn(int $num = null): mixed |
710 | { |
711 | return $this->statement->fetchColumn($num); |
712 | } |
713 | |
714 | /** |
715 | * The method returns the number of rows modified by the last SQL query. |
716 | * |
717 | * @return int |
718 | */ |
719 | public function getCountOfRows(): int |
720 | { |
721 | return $this->statement->rowCount(); |
722 | } |
723 | |
724 | /** |
725 | * The method displays information about the prepared SQL command for debugging purposes. |
726 | * |
727 | * @param bool $debug |
728 | * @return string |
729 | */ |
730 | public function debugDumpParams(bool $debug = false): bool|string |
731 | { |
732 | ob_start(); |
733 | $this->statement->debugDumpParams(); |
734 | $result = ob_get_contents(); |
735 | ob_end_clean(); |
736 | return (!$debug) ?: $result; |
737 | } |
738 | |
739 | /** |
740 | * The method runs an SQL query for execution and returns the number of rows affected during execution. |
741 | * |
742 | * @param mixed $sql The SQL statement to be prepared and run |
743 | * @return Pdo |
744 | */ |
745 | public function exec(mixed $sql): Pdo |
746 | { |
747 | if (!($this->connection->exec($sql))) { |
748 | $this->throwError('Error: The database statement resource is not currently set.'); |
749 | } |
750 | |
751 | return $this; |
752 | } |
753 | |
754 | } |