This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Childish\connection; |
||
3 | |||
4 | use PDO; |
||
5 | use Closure; |
||
6 | use Childish\ChildishException; |
||
7 | use Childish\query\Builder; |
||
8 | use Childish\connection\traits\ManagesTransactions; |
||
9 | use Childish\query\Processor; |
||
10 | use Childish\query\QueryGrammar; |
||
11 | use Childish\support\Tools; |
||
12 | |||
13 | |||
14 | /** |
||
15 | * Connection |
||
16 | * |
||
17 | * @author Pu ShaoWei <[email protected]> |
||
18 | * @date 2017/12/7 |
||
19 | * @package Childish |
||
20 | * @version 1.0 |
||
21 | */ |
||
22 | class Connection implements ConnectionInterface |
||
23 | { |
||
24 | use ManagesTransactions; |
||
25 | /** |
||
26 | * The active PDO connection. |
||
27 | * |
||
28 | * @var \PDO|\Closure |
||
29 | */ |
||
30 | protected $pdo; |
||
31 | |||
32 | /** |
||
33 | * The active PDO connection used for reads. |
||
34 | * |
||
35 | * @var \PDO|\Closure |
||
36 | */ |
||
37 | protected $readPdo; |
||
38 | |||
39 | /** |
||
40 | * The name of the connected database. |
||
41 | * |
||
42 | * @var string |
||
43 | */ |
||
44 | protected $database; |
||
45 | |||
46 | /** |
||
47 | * The table prefix for the connection. |
||
48 | * |
||
49 | * @var string |
||
50 | */ |
||
51 | protected $tablePrefix = ''; |
||
52 | |||
53 | /** |
||
54 | * The database connection configuration options. |
||
55 | * |
||
56 | * @var array |
||
57 | */ |
||
58 | protected $config = []; |
||
59 | |||
60 | /** |
||
61 | * The reconnector instance for the connection. |
||
62 | * |
||
63 | * @var callable |
||
64 | */ |
||
65 | protected $reconnector; |
||
66 | |||
67 | /** |
||
68 | * The query grammar implementation. |
||
69 | * |
||
70 | * @var \Childish\query\QueryGrammar |
||
71 | */ |
||
72 | protected $queryGrammar; |
||
73 | |||
74 | |||
75 | /** |
||
76 | * The query post processor implementation. |
||
77 | * |
||
78 | * @var \childish\query\Processor |
||
79 | */ |
||
80 | protected $postProcessor; |
||
81 | |||
82 | |||
83 | /** |
||
84 | * The default fetch mode of the connection. |
||
85 | * |
||
86 | * @var int |
||
87 | */ |
||
88 | protected $fetchMode = PDO::FETCH_OBJ; |
||
89 | |||
90 | /** |
||
91 | * The number of active transactions. |
||
92 | * |
||
93 | * @var int |
||
94 | */ |
||
95 | protected $transactions = 0; |
||
96 | |||
97 | /** |
||
98 | * Indicates if changes have been made to the database. |
||
99 | * |
||
100 | * @var int |
||
101 | */ |
||
102 | protected $recordsModified = false; |
||
103 | |||
104 | /** |
||
105 | * All of the queries run against the connection. |
||
106 | * |
||
107 | * @var array |
||
108 | */ |
||
109 | protected $queryLog = []; |
||
110 | |||
111 | /** |
||
112 | * Indicates whether queries are being logged. |
||
113 | * |
||
114 | * @var bool |
||
115 | */ |
||
116 | protected $loggingQueries = false; |
||
117 | |||
118 | /** |
||
119 | * Indicates if the connection is in a "dry run". |
||
120 | * |
||
121 | * @var bool |
||
122 | */ |
||
123 | protected $pretending = false; |
||
124 | |||
125 | |||
126 | /** |
||
127 | * The connection resolvers. |
||
128 | * |
||
129 | * @var array |
||
130 | */ |
||
131 | protected static $resolvers = []; |
||
132 | |||
133 | /** |
||
134 | * Create a new database connection instance. |
||
135 | * |
||
136 | * @param \PDO|\Closure $pdo |
||
137 | * @param string $database |
||
138 | * @param string $tablePrefix |
||
139 | * @param array $config |
||
140 | * @return void |
||
0 ignored issues
–
show
|
|||
141 | */ |
||
142 | public function __construct($pdo, $database = '', $tablePrefix = '', array $config = []) |
||
143 | { |
||
144 | $this->pdo = $pdo; |
||
145 | |||
146 | // First we will setup the default properties. We keep track of the DB |
||
147 | // name we are connected to since it is needed when some reflective |
||
148 | // type commands are run such as checking whether a table exists. |
||
149 | $this->database = $database; |
||
150 | |||
151 | $this->tablePrefix = $tablePrefix; |
||
152 | |||
153 | $this->config = $config; |
||
154 | |||
155 | // We need to initialize a query grammar and the query post processors |
||
156 | // which are both very important parts of the database abstractions |
||
157 | // so we initialize these to their default values while starting. |
||
158 | |||
159 | $this->useDefaultQueryGrammar(); |
||
160 | |||
161 | $this->useDefaultPostProcessor(); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Set the query post processor to the default implementation. |
||
166 | * |
||
167 | * @return void |
||
168 | */ |
||
169 | public function useDefaultPostProcessor() |
||
170 | { |
||
171 | $this->postProcessor = $this->getDefaultPostProcessor(); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Get the default post processor instance. |
||
176 | * |
||
177 | * @return \Childish\query\Processor |
||
178 | */ |
||
179 | protected function getDefaultPostProcessor() |
||
180 | { |
||
181 | return new Processor; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Set the query grammar to the default implementation. |
||
186 | * |
||
187 | * @return void |
||
188 | */ |
||
189 | public function useDefaultQueryGrammar() |
||
190 | { |
||
191 | $this->queryGrammar = $this->getDefaultQueryGrammar(); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Get the default query grammar instance. |
||
196 | * |
||
197 | * @return \Childish\query\QueryGrammar |
||
198 | */ |
||
199 | protected function getDefaultQueryGrammar() |
||
200 | { |
||
201 | return new QueryGrammar; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Begin a fluent query against a database table. |
||
206 | * |
||
207 | * @param string $table |
||
208 | * @return \Childish\query\Builder |
||
209 | */ |
||
210 | public function table($table) |
||
211 | { |
||
212 | return $this->query()->from($table); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Get a new query builder instance. |
||
217 | * |
||
218 | * @return \Childish\query\Builder |
||
219 | */ |
||
220 | public function query() |
||
221 | { |
||
222 | return new Builder( |
||
223 | $this, $this->getQueryGrammar(), $this->getPostProcessor() |
||
224 | ); |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * Run a select statement and return a single result. |
||
229 | * |
||
230 | * @param string $query |
||
231 | * @param array $bindings |
||
232 | * @param bool $useReadPdo |
||
233 | * @return mixed |
||
234 | */ |
||
235 | public function selectOne($query, $bindings = [], $useReadPdo = true) |
||
236 | { |
||
237 | $records = $this->select($query, $bindings, $useReadPdo); |
||
238 | |||
239 | return array_shift($records); |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Run a select statement against the database. |
||
244 | * |
||
245 | * @param string $query |
||
246 | * @param array $bindings |
||
247 | * @return array |
||
248 | */ |
||
249 | public function selectFromWriteConnection($query, $bindings = []) |
||
250 | { |
||
251 | return $this->select($query, $bindings, false); |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * Run a select statement against the database. |
||
256 | * |
||
257 | * @param string $query |
||
258 | * @param array $bindings |
||
259 | * @param bool $useReadPdo |
||
260 | * @return array |
||
261 | */ |
||
262 | public function select($query, $bindings = [], $useReadPdo = true) |
||
263 | { |
||
264 | return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { |
||
265 | if ($this->pretending()) { |
||
266 | return []; |
||
267 | } |
||
268 | |||
269 | // For select statements, we'll simply execute the query and return an array |
||
270 | // of the database result set. Each element in the array will be a single |
||
271 | // row from the database table, and will either be an array or objects. |
||
272 | $statement = $this->prepared($this->getPdoForSelect($useReadPdo) |
||
273 | ->prepare($query)); |
||
274 | |||
275 | $this->bindValues($statement, $this->prepareBindings($bindings)); |
||
276 | |||
277 | $statement->execute(); |
||
278 | |||
279 | return $statement->fetchAll(); |
||
280 | }); |
||
281 | } |
||
282 | |||
283 | /** |
||
284 | * Run a select statement against the database and returns a generator. |
||
285 | * |
||
286 | * @param string $query |
||
287 | * @param array $bindings |
||
288 | * @param bool $useReadPdo |
||
289 | * @return \Generator |
||
290 | */ |
||
291 | public function cursor($query, $bindings = [], $useReadPdo = true) |
||
292 | { |
||
293 | $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { |
||
294 | if ($this->pretending()) { |
||
295 | return []; |
||
296 | } |
||
297 | |||
298 | // First we will create a statement for the query. Then, we will set the fetch |
||
299 | // mode and prepare the bindings for the query. Once that's done we will be |
||
300 | // ready to execute the query against the database and return the cursor. |
||
301 | $statement = $this->prepared($this->getPdoForSelect($useReadPdo) |
||
302 | ->prepare($query)); |
||
303 | |||
304 | $this->bindValues( |
||
305 | $statement, $this->prepareBindings($bindings) |
||
306 | ); |
||
307 | |||
308 | // Next, we'll execute the query against the database and return the statement |
||
309 | // so we can return the cursor. The cursor will use a PHP generator to give |
||
310 | // back one row at a time without using a bunch of memory to render them. |
||
311 | $statement->execute(); |
||
312 | |||
313 | return $statement; |
||
314 | }); |
||
315 | |||
316 | while ($record = $statement->fetch()) { |
||
317 | yield $record; |
||
318 | } |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * Configure the PDO prepared statement. |
||
323 | * |
||
324 | * @param \PDOStatement $statement |
||
325 | * @return \PDOStatement |
||
326 | */ |
||
327 | protected function prepared($statement) |
||
328 | { |
||
329 | $statement->setFetchMode($this->fetchMode); |
||
330 | |||
331 | return $statement; |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Get the PDO connection to use for a select query. |
||
336 | * |
||
337 | * @param bool $useReadPdo |
||
338 | * @return \PDO |
||
339 | */ |
||
340 | protected function getPdoForSelect($useReadPdo = true) |
||
341 | { |
||
342 | return $useReadPdo ? $this->getReadPdo() : $this->getPdo(); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Run an insert statement against the database. |
||
347 | * |
||
348 | * @param string $query |
||
349 | * @param array $bindings |
||
350 | * @return bool |
||
351 | */ |
||
352 | public function insert($query, $bindings = []) |
||
353 | { |
||
354 | return $this->statement($query, $bindings); |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Run an update statement against the database. |
||
359 | * |
||
360 | * @param string $query |
||
361 | * @param array $bindings |
||
362 | * @return int |
||
363 | */ |
||
364 | public function update($query, $bindings = []) |
||
365 | { |
||
366 | return $this->affectingStatement($query, $bindings); |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Run a delete statement against the database. |
||
371 | * |
||
372 | * @param string $query |
||
373 | * @param array $bindings |
||
374 | * @return int |
||
375 | */ |
||
376 | public function delete($query, $bindings = []) |
||
377 | { |
||
378 | return $this->affectingStatement($query, $bindings); |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * Execute an SQL statement and return the boolean result. |
||
383 | * |
||
384 | * @param string $query |
||
385 | * @param array $bindings |
||
386 | * @return bool |
||
387 | */ |
||
388 | public function statement($query, $bindings = []) |
||
389 | { |
||
390 | return $this->run($query, $bindings, function ($query, $bindings) { |
||
391 | if ($this->pretending()) { |
||
392 | return true; |
||
393 | } |
||
394 | |||
395 | $statement = $this->getPdo()->prepare($query); |
||
396 | |||
397 | $this->bindValues($statement, $this->prepareBindings($bindings)); |
||
398 | |||
399 | $this->recordsHaveBeenModified(); |
||
400 | |||
401 | return $statement->execute(); |
||
402 | }); |
||
403 | } |
||
404 | |||
405 | /** |
||
406 | * Run an SQL statement and get the number of rows affected. |
||
407 | * |
||
408 | * @param string $query |
||
409 | * @param array $bindings |
||
410 | * @return int |
||
411 | */ |
||
412 | public function affectingStatement($query, $bindings = []) |
||
413 | { |
||
414 | return $this->run($query, $bindings, function ($query, $bindings) { |
||
415 | if ($this->pretending()) { |
||
416 | return 0; |
||
417 | } |
||
418 | |||
419 | // For update or delete statements, we want to get the number of rows affected |
||
420 | // by the statement and return that back to the developer. We'll first need |
||
421 | // to execute the statement and then we'll use PDO to fetch the affected. |
||
422 | $statement = $this->getPdo()->prepare($query); |
||
423 | |||
424 | $this->bindValues($statement, $this->prepareBindings($bindings)); |
||
425 | |||
426 | $statement->execute(); |
||
427 | |||
428 | $this->recordsHaveBeenModified( |
||
429 | ($count = $statement->rowCount()) > 0 |
||
430 | ); |
||
431 | |||
432 | return $count; |
||
433 | }); |
||
434 | } |
||
435 | |||
436 | /** |
||
437 | * Run a raw, unprepared query against the PDO connection. |
||
438 | * |
||
439 | * @param string $query |
||
440 | * @return bool |
||
441 | */ |
||
442 | public function unprepared($query) |
||
443 | { |
||
444 | return $this->run($query, [], function ($query) { |
||
445 | if ($this->pretending()) { |
||
446 | return true; |
||
447 | } |
||
448 | |||
449 | $this->recordsHaveBeenModified( |
||
450 | $change = ($this->getPdo()->exec($query) === false ? false : true) |
||
451 | ); |
||
452 | |||
453 | return $change; |
||
454 | }); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Execute the given callback in "dry run" mode. |
||
459 | * |
||
460 | * @param \Closure $callback |
||
461 | * @return array |
||
462 | */ |
||
463 | public function pretend(Closure $callback) |
||
464 | { |
||
465 | return $this->withFreshQueryLog(function () use ($callback) { |
||
466 | $this->pretending = true; |
||
467 | |||
468 | // Basically to make the database connection "pretend", we will just return |
||
469 | // the default values for all the query methods, then we will return an |
||
470 | // array of queries that were "executed" within the Closure callback. |
||
471 | $callback($this); |
||
472 | |||
473 | $this->pretending = false; |
||
474 | |||
475 | return $this->queryLog; |
||
476 | }); |
||
477 | } |
||
478 | |||
479 | /** |
||
480 | * Execute the given callback in "dry run" mode. |
||
481 | * |
||
482 | * @param \Closure $callback |
||
483 | * @return array |
||
484 | */ |
||
485 | protected function withFreshQueryLog($callback) |
||
486 | { |
||
487 | $loggingQueries = $this->loggingQueries; |
||
488 | |||
489 | // First we will back up the value of the logging queries property and then |
||
490 | // we'll be ready to run callbacks. This query log will also get cleared |
||
491 | // so we will have a new log of all the queries that are executed now. |
||
492 | $this->enableQueryLog(); |
||
493 | |||
494 | $this->queryLog = []; |
||
495 | |||
496 | // Now we'll execute this callback and capture the result. Once it has been |
||
497 | // executed we will restore the value of query logging and give back the |
||
498 | // value of hte callback so the original callers can have the results. |
||
499 | $result = $callback(); |
||
500 | |||
501 | $this->loggingQueries = $loggingQueries; |
||
502 | |||
503 | return $result; |
||
504 | } |
||
505 | |||
506 | /** |
||
507 | * Bind values to their parameters in the given statement. |
||
508 | * |
||
509 | * @param \PDOStatement $statement |
||
510 | * @param array $bindings |
||
511 | * @return void |
||
512 | */ |
||
513 | public function bindValues($statement, $bindings) |
||
514 | { |
||
515 | foreach ($bindings as $key => $value) { |
||
516 | $statement->bindValue( |
||
517 | is_string($key) ? $key : $key + 1, $value, |
||
518 | is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR |
||
519 | ); |
||
520 | } |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * Prepare the query bindings for execution. |
||
525 | * |
||
526 | * @param array $bindings |
||
527 | * @return array |
||
528 | */ |
||
529 | public function prepareBindings(array $bindings) |
||
530 | { |
||
531 | foreach ($bindings as $key => $value) { |
||
532 | // We need to transform all instances of DateTimeInterface into the actual |
||
533 | // date string. Each query grammar maintains its own date string format |
||
534 | // so we'll just ask the grammar for the format to get from the date. |
||
535 | if (is_bool($value)) { |
||
536 | $bindings[$key] = (int)$value; |
||
537 | } |
||
538 | } |
||
539 | |||
540 | return $bindings; |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * Run a SQL statement and log its execution context. |
||
545 | * |
||
546 | * @param string $query |
||
547 | * @param array $bindings |
||
548 | * @param \Closure $callback |
||
549 | * @return mixed |
||
550 | * @throws \childish\ChildishException |
||
551 | */ |
||
552 | protected function run($query, $bindings, Closure $callback) |
||
553 | { |
||
554 | $this->reconnectIfMissingConnection(); |
||
555 | |||
556 | $start = microtime(true); |
||
557 | |||
558 | // Here we will run this query. If an exception occurs we'll determine if it was |
||
559 | // caused by a connection that has been lost. If that is the cause, we'll try |
||
560 | // to re-establish connection and re-run the query with a fresh connection. |
||
561 | try { |
||
562 | $result = $this->runQueryCallback($query, $bindings, $callback); |
||
563 | } catch (ChildishException $e) { |
||
564 | $result = $this->handleQueryException( |
||
565 | $e, $query, $bindings, $callback |
||
566 | ); |
||
567 | } |
||
568 | |||
569 | // Once we have run the query we will calculate the time that it took to run and |
||
570 | // then log the query, bindings, and execution time so we will report them on |
||
571 | // the event that the developer needs them. We'll log time in milliseconds. |
||
572 | $this->logQuery( |
||
573 | $query, $bindings, $this->getElapsedTime($start) |
||
574 | ); |
||
575 | |||
576 | return $result; |
||
577 | } |
||
578 | |||
579 | /** |
||
580 | * Run a SQL statement. |
||
581 | * |
||
582 | * @param string $query |
||
583 | * @param array $bindings |
||
584 | * @param \Closure $callback |
||
585 | * @return mixed |
||
586 | * @throws \Childish\ChildishException |
||
587 | */ |
||
588 | protected function runQueryCallback($query, $bindings, Closure $callback) |
||
589 | { |
||
590 | // To execute the statement, we'll simply call the callback, which will actually |
||
591 | // run the SQL against the PDO connection. Then we can calculate the time it |
||
592 | // took to execute and log the query SQL, bindings and time in our memory. |
||
593 | try { |
||
594 | |||
595 | $result = $callback($query, $bindings); |
||
596 | } |
||
597 | |||
598 | // If an exception occurs when attempting to run a query, we'll format the error |
||
599 | // message to include the bindings with SQL, which will make this exception a |
||
600 | // lot more helpful to the developer instead of just the database's errors. |
||
601 | catch (\Exception $e) { |
||
602 | throw new ChildishException( |
||
603 | $query, $this->prepareBindings($bindings), $e |
||
604 | ); |
||
605 | } |
||
606 | |||
607 | return $result; |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Log a query in the connection's query log. |
||
612 | * |
||
613 | * @param string $query |
||
614 | * @param array $bindings |
||
615 | * @param float|null $time |
||
616 | * @return void |
||
617 | */ |
||
618 | public function logQuery($query, $bindings, $time = null) |
||
619 | { |
||
620 | if ($this->loggingQueries) { |
||
621 | $this->queryLog[] = compact('query', 'bindings', 'time'); |
||
622 | } |
||
623 | } |
||
624 | |||
625 | /** |
||
626 | * Get the elapsed time since a given starting point. |
||
627 | * |
||
628 | * @param int $start |
||
629 | * @return float |
||
630 | */ |
||
631 | protected function getElapsedTime($start) |
||
632 | { |
||
633 | return round((microtime(true) - $start) * 1000, 2); |
||
634 | } |
||
635 | |||
636 | /** |
||
637 | * Handle a query exception. |
||
638 | * |
||
639 | * @param \Exception $e |
||
640 | * @param string $query |
||
641 | * @param array $bindings |
||
642 | * @param \Closure $callback |
||
643 | * @return mixed |
||
644 | * @throws \Exception |
||
645 | */ |
||
646 | protected function handleQueryException($e, $query, $bindings, Closure $callback) |
||
647 | { |
||
648 | if ($this->transactions >= 1) { |
||
649 | throw $e; |
||
650 | } |
||
651 | |||
652 | return $this->tryAgainIfCausedByLostConnection( |
||
653 | $e, $query, $bindings, $callback |
||
0 ignored issues
–
show
$e of type object<Exception> is not a sub-type of object<Childish\ChildishException> . It seems like you assume a child class of the class Exception to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() |
|||
654 | ); |
||
655 | } |
||
656 | |||
657 | /** |
||
658 | * Handle a query exception that occurred during query execution. |
||
659 | * |
||
660 | * @param \Childish\ChildishException $e |
||
661 | * @param $query |
||
662 | * @param $bindings |
||
663 | * @param \Closure $callback |
||
664 | * @return mixed |
||
665 | */ |
||
666 | protected function tryAgainIfCausedByLostConnection(ChildishException $e, $query, $bindings, Closure $callback) |
||
667 | { |
||
668 | if ($this->causedByLostConnection($e->getPrevious())) { |
||
669 | $this->reconnect(); |
||
670 | |||
671 | return $this->runQueryCallback($query, $bindings, $callback); |
||
672 | } |
||
673 | |||
674 | throw $e; |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * Reconnect to the database. |
||
679 | * |
||
680 | * @return void |
||
681 | * @throws \LogicException |
||
682 | */ |
||
683 | public function reconnect() |
||
684 | { |
||
685 | if (is_callable($this->reconnector)) { |
||
686 | return call_user_func($this->reconnector, $this); |
||
687 | } |
||
688 | |||
689 | throw new \LogicException('Lost connection and no reconnector available.'); |
||
690 | } |
||
691 | |||
692 | /** |
||
693 | * Reconnect to the database if a PDO connection is missing. |
||
694 | * |
||
695 | * @return void |
||
696 | */ |
||
697 | protected function reconnectIfMissingConnection() |
||
698 | { |
||
699 | if (is_null($this->pdo)) { |
||
700 | $this->reconnect(); |
||
701 | } |
||
702 | } |
||
703 | |||
704 | /** |
||
705 | * Disconnect from the underlying PDO connection. |
||
706 | * |
||
707 | * @return void |
||
708 | */ |
||
709 | public function disconnect() |
||
710 | { |
||
711 | $this->setPdo(null)->setReadPdo(null); |
||
712 | } |
||
713 | |||
714 | /** |
||
715 | * Fire the given event if possible. |
||
716 | * |
||
717 | * @param mixed $event |
||
718 | * @return void |
||
719 | */ |
||
720 | protected function event($event) |
||
721 | { |
||
722 | if (isset($this->events)) { |
||
723 | $this->events->dispatch($event); |
||
0 ignored issues
–
show
The property
events does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
724 | } |
||
725 | } |
||
726 | |||
727 | /** |
||
728 | * Indicate if any records have been modified. |
||
729 | * |
||
730 | * @param bool $value |
||
731 | * @return void |
||
732 | */ |
||
733 | public function recordsHaveBeenModified($value = true) |
||
734 | { |
||
735 | if (!$this->recordsModified) { |
||
736 | $this->recordsModified = $value; |
||
0 ignored issues
–
show
The property
$recordsModified was declared of type integer , but $value is of type boolean . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
737 | } |
||
738 | } |
||
739 | |||
740 | /** |
||
741 | * Get the current PDO connection. |
||
742 | * |
||
743 | * @return \PDO |
||
744 | */ |
||
745 | public function getPdo() |
||
746 | { |
||
747 | if ($this->pdo instanceof Closure) { |
||
748 | return $this->pdo = call_user_func($this->pdo); |
||
749 | } |
||
750 | |||
751 | return $this->pdo; |
||
752 | } |
||
753 | |||
754 | /** |
||
755 | * Get the current PDO connection used for reading. |
||
756 | * |
||
757 | * @return \PDO |
||
758 | */ |
||
759 | public function getReadPdo() |
||
760 | { |
||
761 | if ($this->transactions > 0) { |
||
762 | return $this->getPdo(); |
||
763 | } |
||
764 | |||
765 | if ($this->getConfig('sticky') && $this->recordsModified) { |
||
766 | return $this->getPdo(); |
||
767 | } |
||
768 | |||
769 | if ($this->readPdo instanceof Closure) { |
||
770 | return $this->readPdo = call_user_func($this->readPdo); |
||
771 | } |
||
772 | |||
773 | return $this->readPdo ? : $this->getPdo(); |
||
774 | } |
||
775 | |||
776 | /** |
||
777 | * Set the PDO connection. |
||
778 | * |
||
779 | * @param \PDO|\Closure|null $pdo |
||
780 | * @return $this |
||
781 | */ |
||
782 | public function setPdo($pdo) |
||
783 | { |
||
784 | $this->transactions = 0; |
||
785 | |||
786 | $this->pdo = $pdo; |
||
787 | |||
788 | return $this; |
||
789 | } |
||
790 | |||
791 | /** |
||
792 | * Set the PDO connection used for reading. |
||
793 | * |
||
794 | * @param \PDO||\Closure|null $pdo |
||
0 ignored issues
–
show
The doc-type
\PDO||\Closure|null could not be parsed: Unknown type name "|" at position 5. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
795 | * @return $this |
||
796 | */ |
||
797 | public function setReadPdo($pdo) |
||
798 | { |
||
799 | $this->readPdo = $pdo; |
||
800 | |||
801 | return $this; |
||
802 | } |
||
803 | |||
804 | /** |
||
805 | * Set the reconnect instance on the connection. |
||
806 | * |
||
807 | * @param callable $reconnector |
||
808 | * @return $this |
||
809 | */ |
||
810 | public function setReconnector(callable $reconnector) |
||
811 | { |
||
812 | $this->reconnector = $reconnector; |
||
813 | |||
814 | return $this; |
||
815 | } |
||
816 | |||
817 | /** |
||
818 | * Get the database connection name. |
||
819 | * |
||
820 | * @return string|null |
||
821 | */ |
||
822 | public function getName() |
||
823 | { |
||
824 | return $this->getConfig('name'); |
||
825 | } |
||
826 | |||
827 | /** |
||
828 | * Get an option from the configuration options. |
||
829 | * |
||
830 | * @param string|null $option |
||
831 | * @return mixed |
||
832 | */ |
||
833 | public function getConfig($option = null) |
||
834 | { |
||
835 | return Tools::get($this->config, $option); |
||
836 | } |
||
837 | |||
838 | /** |
||
839 | * Get the PDO driver name. |
||
840 | * |
||
841 | * @return string |
||
842 | */ |
||
843 | public function getDriverName() |
||
844 | { |
||
845 | return $this->getConfig('driver'); |
||
846 | } |
||
847 | |||
848 | /** |
||
849 | * Get the query grammar used by the connection. |
||
850 | * |
||
851 | * @return \Childish\query\QueryGrammar |
||
852 | */ |
||
853 | public function getQueryGrammar() |
||
854 | { |
||
855 | return $this->queryGrammar; |
||
856 | } |
||
857 | |||
858 | /** |
||
859 | * Set the query grammar used by the connection. |
||
860 | * |
||
861 | * @param \Childish\query\QueryGrammar $grammar |
||
862 | * @return void |
||
863 | */ |
||
864 | public function setQueryGrammar(QueryGrammar $grammar) |
||
865 | { |
||
866 | $this->queryGrammar = $grammar; |
||
867 | } |
||
868 | |||
869 | |||
870 | /** |
||
871 | * Get the query post processor used by the connection. |
||
872 | * |
||
873 | * @return \childish\query\Processor |
||
874 | */ |
||
875 | public function getPostProcessor() |
||
876 | { |
||
877 | return $this->postProcessor; |
||
878 | } |
||
879 | |||
880 | /** |
||
881 | * Set the query post processor used by the connection. |
||
882 | * |
||
883 | * @param \childish\query\Processor $processor |
||
884 | * @return void |
||
885 | */ |
||
886 | public function setPostProcessor(Processor $processor) |
||
887 | { |
||
888 | $this->postProcessor = $processor; |
||
889 | } |
||
890 | |||
891 | /** |
||
892 | * Determine if the connection in a "dry run". |
||
893 | * |
||
894 | * @return bool |
||
895 | */ |
||
896 | public function pretending() |
||
897 | { |
||
898 | return $this->pretending === true; |
||
899 | } |
||
900 | |||
901 | /** |
||
902 | * Get the connection query log. |
||
903 | * |
||
904 | * @return array |
||
905 | */ |
||
906 | public function getQueryLog() |
||
907 | { |
||
908 | return $this->queryLog; |
||
909 | } |
||
910 | |||
911 | /** |
||
912 | * Clear the query log. |
||
913 | * |
||
914 | * @return void |
||
915 | */ |
||
916 | public function flushQueryLog() |
||
917 | { |
||
918 | $this->queryLog = []; |
||
919 | } |
||
920 | |||
921 | /** |
||
922 | * Enable the query log on the connection. |
||
923 | * |
||
924 | * @return void |
||
925 | */ |
||
926 | public function enableQueryLog() |
||
927 | { |
||
928 | $this->loggingQueries = true; |
||
929 | } |
||
930 | |||
931 | /** |
||
932 | * Disable the query log on the connection. |
||
933 | * |
||
934 | * @return void |
||
935 | */ |
||
936 | public function disableQueryLog() |
||
937 | { |
||
938 | $this->loggingQueries = false; |
||
939 | } |
||
940 | |||
941 | /** |
||
942 | * Determine whether we're logging queries. |
||
943 | * |
||
944 | * @return bool |
||
945 | */ |
||
946 | public function logging() |
||
947 | { |
||
948 | return $this->loggingQueries; |
||
949 | } |
||
950 | |||
951 | /** |
||
952 | * Get the name of the connected database. |
||
953 | * |
||
954 | * @return string |
||
955 | */ |
||
956 | public function getDatabaseName() |
||
957 | { |
||
958 | return $this->database; |
||
959 | } |
||
960 | |||
961 | /** |
||
962 | * Set the name of the connected database. |
||
963 | * |
||
964 | * @param string $database |
||
965 | * @return string |
||
966 | */ |
||
967 | public function setDatabaseName($database) |
||
968 | { |
||
969 | $this->database = $database; |
||
970 | } |
||
971 | |||
972 | /** |
||
973 | * Get the table prefix for the connection. |
||
974 | * |
||
975 | * @return string |
||
976 | */ |
||
977 | public function getTablePrefix() |
||
978 | { |
||
979 | return $this->tablePrefix; |
||
980 | } |
||
981 | |||
982 | /** |
||
983 | * Set the table prefix in use by the connection. |
||
984 | * |
||
985 | * @param string $prefix |
||
986 | * @return void |
||
987 | */ |
||
988 | public function setTablePrefix($prefix) |
||
989 | { |
||
990 | $this->tablePrefix = $prefix; |
||
991 | |||
992 | $this->getQueryGrammar()->setTablePrefix($prefix); |
||
993 | } |
||
994 | |||
995 | /** |
||
996 | * Set the table prefix and return the grammar. |
||
997 | * |
||
998 | * @param \Childish\query\QueryGrammar $grammar |
||
999 | * @return \Childish\query\QueryGrammar |
||
1000 | */ |
||
1001 | public function withTablePrefix(QueryGrammar $grammar) |
||
1002 | { |
||
1003 | $grammar->setTablePrefix($this->tablePrefix); |
||
1004 | |||
1005 | return $grammar; |
||
1006 | } |
||
1007 | |||
1008 | /** |
||
1009 | * Register a connection resolver. |
||
1010 | * |
||
1011 | * @param string $driver |
||
1012 | * @param \Closure $callback |
||
1013 | * @return void |
||
1014 | */ |
||
1015 | public static function resolverFor($driver, Closure $callback) |
||
1016 | { |
||
1017 | static::$resolvers[$driver] = $callback; |
||
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * Get the connection resolver for the given driver. |
||
1022 | * |
||
1023 | * @param string $driver |
||
1024 | * @return mixed |
||
1025 | */ |
||
1026 | public static function getResolver($driver) |
||
1027 | { |
||
1028 | return static::$resolvers[$driver] ?? null; |
||
1029 | } |
||
1030 | |||
1031 | /** |
||
1032 | * Call the given Closure with the given value then return the value. |
||
1033 | * |
||
1034 | * @param mixed $value |
||
1035 | * @param callable|null $callback |
||
1036 | * @return mixed |
||
1037 | */ |
||
1038 | public function higherOrderTap($value, $callback = null) |
||
1039 | { |
||
1040 | if (is_null($callback) === false) { |
||
1041 | $callback($value); |
||
1042 | } |
||
1043 | return $value; |
||
1044 | } |
||
1045 | |||
1046 | /** |
||
1047 | * Determine if the given exception was caused by a lost connection. |
||
1048 | * |
||
1049 | * @param \Exception $e |
||
1050 | * @return bool |
||
1051 | */ |
||
1052 | protected function causedByLostConnection(\Exception $e) |
||
1053 | { |
||
1054 | $message = $e->getMessage(); |
||
1055 | |||
1056 | return Tools::contains($message, [ |
||
1057 | 'server has gone away', |
||
1058 | 'no connection to the server', |
||
1059 | 'Lost connection', |
||
1060 | 'is dead or not enabled', |
||
1061 | 'Error while sending', |
||
1062 | 'decryption failed or bad record mac', |
||
1063 | 'server closed the connection unexpectedly', |
||
1064 | 'SSL connection has been closed unexpectedly', |
||
1065 | 'Error writing data to the connection', |
||
1066 | 'Resource deadlock avoided', |
||
1067 | 'Transaction() on null', |
||
1068 | 'child connection forced to terminate due to client_idle_limit', |
||
1069 | ]); |
||
1070 | } |
||
1071 | } |
Adding a
@return
annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.