fillDebugSqlParameters($sql, $parameters) ]); try { if (false !== ( $statement = $this->prepare($sql) )) { $statement->setFetchMode(\PDO::FETCH_ASSOC); $this->execute($statement, $parameters, false); } } catch (\Throwable $e) { throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters)); } return $statement; } public function __destruct() { if ($this->onClose ?? null) { call_user_func($this->onClose, $this); } } public function runQuery(string $sql, array $parameters = []): ? static { static::$dump && call_user_func_array(static::$dump, [ $this->fillDebugSqlParameters($sql, $parameters) ]); try { if (false !== ( $statement = $this->prepare($sql) )) { return $this->execute($statement, $parameters, true); } } catch(\PDOException $pdo) { if (!str_starts_with($pdo->getMessage(), 'There is no active transaction')) { throw $pdo; } } catch (\Throwable $e) { throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters), (int) $e->getCode(), $e); } return null; } public function runInsertQuery(string $sql, array $parameters = []) : ? static { return $this->runQuery($sql, $parameters); } public function runUpdateQuery(string $sql, array $parameters = []) : ? static { return $this->runQuery($sql, $parameters); } public function runDeleteQuery(string $sql, array $parameters = []) : ? static { return $this->runQuery($sql, $parameters); } public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true) : ? static { $this->executionStatus = false; $this->lastInsertId = null; try { if (! $this->inTransaction()) { $this->beginTransaction(); } $this->bindVariables($statement, $parameters); $this->executionStatus = $statement->execute(); if ( $this->executionStatus ) { $this->lastInsertId = $this->lastInsertId(); $this->rowCount = $statement->rowCount(); if ( $commit ) { $this->commit(); } return $this; } else { throw new \PDOException($statement->errorCode() . " - " . json_encode($statement->errorInfo())); } } catch (\PDOException $e) { $this->rollback(); throw $e; } } protected function bindVariables(PDOStatement $statement, array &$parameters) : void { if ($parameters) { if (array_is_list($parameters)) { $parameters = array_combine(range(1, count($parameters)), array_values($parameters)); } else { foreach ($parameters as $key => $value) { $type = match (strtolower(gettype($value))) { "boolean", "integer" => Pdo::PARAM_INT, "null" => Pdo::PARAM_NULL, default => Pdo::PARAM_STR, }; $statement->bindValue($key, $value, $type); } } } } protected function fillDebugSqlParameters(string $sql, array $parameters) : string { $parameters = array_reverse($parameters); return str_replace(array_keys($parameters), array_map(fn($e) => is_numeric($e) ? $e : ( is_bool($e) ? (int) $e : $this->quote($e) ), array_values($parameters)), $sql); } }