stwalkerster /
waca
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * @param string $db |
||
| 5 | * @return PdoDatabase |
||
| 6 | * @throws Exception |
||
| 7 | */ |
||
| 8 | function gGetDb($db = "acc") |
||
| 9 | { |
||
| 10 | return PdoDatabase::getDatabaseConnection($db); |
||
| 11 | } |
||
| 12 | |||
| 13 | class PdoDatabase extends PDO |
||
| 14 | { |
||
| 15 | /** |
||
| 16 | * @var PdoDatabase[] |
||
| 17 | */ |
||
| 18 | private static $connections = array(); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * @var bool True if a transaction is active |
||
| 22 | */ |
||
| 23 | protected $hasActiveTransaction = false; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * Summary of $queryLogStatement |
||
| 27 | * @var PDOStatement |
||
| 28 | */ |
||
| 29 | private $queryLogStatement; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @param string $connectionName |
||
| 33 | * @return PdoDatabase |
||
| 34 | * @throws Exception |
||
| 35 | */ |
||
| 36 | public static function getDatabaseConnection($connectionName) |
||
| 37 | { |
||
| 38 | if (!isset(self::$connections[$connectionName])) { |
||
| 39 | global $cDatabaseConfig; |
||
| 40 | |||
| 41 | if (!array_key_exists($connectionName, $cDatabaseConfig)) { |
||
| 42 | throw new Exception("Database configuration not found for alias $connectionName"); |
||
| 43 | } |
||
| 44 | |||
| 45 | try { |
||
| 46 | $databaseObject = new PdoDatabase( |
||
| 47 | $cDatabaseConfig[$connectionName]["dsrcname"], |
||
| 48 | $cDatabaseConfig[$connectionName]["username"], |
||
| 49 | $cDatabaseConfig[$connectionName]["password"], |
||
| 50 | $cDatabaseConfig[$connectionName]["options"] |
||
| 51 | ); |
||
| 52 | } |
||
| 53 | catch (PDOException $ex) { |
||
| 54 | // wrap around any potential stack traces which may include passwords |
||
| 55 | throw new Exception("Error connecting to database '$connectionName': " . $ex->getMessage()); |
||
| 56 | } |
||
| 57 | |||
| 58 | $databaseObject->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
||
| 59 | |||
| 60 | // emulating prepared statements gives a performance boost on MySQL. |
||
| 61 | // |
||
| 62 | // however, our version of PDO doesn't seem to understand parameter types when emulating |
||
| 63 | // the prepared statements, so we're forced to turn this off for now. |
||
| 64 | // -- stw 2014-02-11 |
||
| 65 | $databaseObject->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); |
||
| 66 | |||
| 67 | self::$connections[$connectionName] = $databaseObject; |
||
| 68 | } |
||
| 69 | |||
| 70 | return self::$connections[$connectionName]; |
||
| 71 | } |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Determines if this connection has a transaction in progress or not |
||
| 75 | * @return boolean true if there is a transaction in progress. |
||
| 76 | */ |
||
| 77 | public function hasActiveTransaction() |
||
| 78 | { |
||
| 79 | return $this->hasActiveTransaction; |
||
| 80 | } |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Summary of beginTransaction |
||
| 84 | * @return bool |
||
| 85 | */ |
||
| 86 | public function beginTransaction() |
||
| 87 | { |
||
| 88 | // Override the pre-existing method, which doesn't stop you from |
||
| 89 | // starting transactions within transactions - which doesn't work and |
||
| 90 | // will throw an exception. This eliminates the need to catch exceptions |
||
| 91 | // all over the rest of the code |
||
| 92 | if ($this->hasActiveTransaction) { |
||
| 93 | return false; |
||
| 94 | } |
||
| 95 | else { |
||
| 96 | // set the transaction isolation level for every transaction. |
||
| 97 | $this->exec("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); |
||
| 98 | |||
| 99 | // start a new transaction, and return whether or not the start was |
||
| 100 | // successful |
||
| 101 | $this->hasActiveTransaction = parent::beginTransaction(); |
||
| 102 | return $this->hasActiveTransaction; |
||
| 103 | } |
||
| 104 | } |
||
| 105 | |||
| 106 | /** |
||
| 107 | * Commits the active transaction |
||
| 108 | */ |
||
| 109 | public function commit() |
||
| 110 | { |
||
| 111 | parent::commit(); |
||
| 112 | $this->hasActiveTransaction = false; |
||
| 113 | } |
||
| 114 | |||
| 115 | /** |
||
| 116 | * Rolls back a transaction |
||
| 117 | */ |
||
| 118 | public function rollBack() |
||
| 119 | { |
||
| 120 | parent::rollback(); |
||
| 121 | $this->hasActiveTransaction = false; |
||
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Summary of transactionally |
||
| 126 | * @param Closure $method |
||
| 127 | */ |
||
| 128 | public function transactionally($method) |
||
| 129 | { |
||
| 130 | if (!$this->beginTransaction()) { |
||
| 131 | BootstrapSkin::displayAlertBox("Error starting database transaction.", "alert-error", "Database transaction error", true, false); |
||
| 132 | BootstrapSkin::displayInternalFooter(); |
||
| 133 | die(); |
||
| 134 | } |
||
| 135 | |||
| 136 | try { |
||
| 137 | $method(); |
||
| 138 | |||
| 139 | $this->commit(); |
||
| 140 | } |
||
| 141 | catch (TransactionException $ex) { |
||
| 142 | $this->rollBack(); |
||
| 143 | |||
| 144 | BootstrapSkin::displayAlertBox($ex->getMessage(), $ex->getAlertType(), $ex->getTitle(), true, false); |
||
| 145 | |||
| 146 | // TODO: yuk. |
||
| 147 | if (defined("PUBLICMODE")) { |
||
| 148 | BootstrapSkin::displayPublicFooter(); |
||
| 149 | } |
||
| 150 | else { |
||
| 151 | BootstrapSkin::displayInternalFooter(); |
||
| 152 | } |
||
| 153 | |||
| 154 | die(); |
||
| 155 | } |
||
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * Prepares a statement for execution. |
||
| 160 | * @param string $statement |
||
| 161 | * @param array $driver_options |
||
| 162 | * @return PDOStatement |
||
| 163 | */ |
||
| 164 | public function prepare($statement, $driver_options = array()) |
||
|
0 ignored issues
–
show
The parameter $driver_options is not named in camelCase.
This check marks parameter names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes Loading history...
|
|||
| 165 | { |
||
| 166 | global $enableQueryLog; |
||
| 167 | if ($enableQueryLog) { |
||
| 168 | try { |
||
| 169 | if ($this->queryLogStatement === null) { |
||
| 170 | $this->queryLogStatement = |
||
| 171 | parent::prepare(<<<SQL |
||
| 172 | INSERT INTO applicationlog (source, message, stack, request, request_ts) |
||
| 173 | VALUES (:source, :message, :stack, :request, :rqts); |
||
| 174 | SQL |
||
| 175 | ); |
||
| 176 | } |
||
| 177 | |||
| 178 | $this->queryLogStatement->execute( |
||
| 179 | array( |
||
| 180 | ":source" => "QueryLog", |
||
| 181 | ":message" => $statement, |
||
| 182 | ":stack" => DebugHelper::getBacktrace(), |
||
| 183 | ":request" => $_SERVER["REQUEST_URI"], |
||
| 184 | ":rqts" => $_SERVER["REQUEST_TIME_FLOAT"], |
||
| 185 | ) |
||
| 186 | ); |
||
| 187 | } |
||
| 188 | catch (Exception $ex) { |
||
| 189 | trigger_error("Error logging query. Disabling for this request. " . $ex->getMessage(), E_USER_NOTICE); |
||
| 190 | $enableQueryLog = false; |
||
| 191 | } |
||
| 192 | } |
||
| 193 | |||
| 194 | return parent::prepare($statement, $driver_options); |
||
| 195 | } |
||
| 196 | } |
||
| 197 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: