Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
39.53% |
17 / 43 |
|
38.46% |
10 / 26 |
CRAP | |
0.00% |
0 / 1 |
| common_persistence_sql_Platform | |
39.53% |
17 / 43 |
|
38.46% |
10 / 26 |
228.96 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getQueryBuilder | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| limitStatement | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getPhpTextValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getObjectTypeCondition | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getNullString | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| isNullCondition | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| quoteIdentifier | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| schemaToSql | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| toDropSql | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getMigrateSchemaSql | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| migrateSchema | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
| getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getNowExpression | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getDateTimeFormatString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getDateTimeTzFormatString | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getSqlFunction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getWriteLockSQL | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getReadLockSQL | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| beginTransaction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setTransactionIsolation | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| getTransactionIsolation | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| isTransactionActive | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| rollBack | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| commit | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
| getTruncateTableSql | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * This program is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU General Public License |
| 6 | * as published by the Free Software Foundation; under version 2 |
| 7 | * of the License (non-upgradable). |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | * |
| 18 | * Copyright (c) 2014-2017 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); |
| 19 | * |
| 20 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 21 | * @license GPLv2 |
| 22 | * @package generis |
| 23 | * |
| 24 | */ |
| 25 | |
| 26 | use Doctrine\DBAL\Connection; |
| 27 | use Doctrine\DBAL\DBALException; |
| 28 | use Doctrine\DBAL\Schema\Schema; |
| 29 | |
| 30 | class common_persistence_sql_Platform |
| 31 | { |
| 32 | public const TRANSACTION_PLATFORM_DEFAULT = 0; |
| 33 | |
| 34 | public const TRANSACTION_READ_UNCOMMITTED = Connection::TRANSACTION_READ_UNCOMMITTED; |
| 35 | |
| 36 | public const TRANSACTION_READ_COMMITTED = Connection::TRANSACTION_READ_COMMITTED; |
| 37 | |
| 38 | public const TRANSACTION_REPEATABLE_READ = Connection::TRANSACTION_REPEATABLE_READ; |
| 39 | |
| 40 | public const TRANSACTION_SERIALIZABLE = Connection::TRANSACTION_SERIALIZABLE; |
| 41 | |
| 42 | protected $dbalPlatform; |
| 43 | |
| 44 | /** @var \Doctrine\DBAL\Connection */ |
| 45 | protected $dbalConnection; |
| 46 | |
| 47 | |
| 48 | /** |
| 49 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 50 | * @param $dbalConnection \Doctrine\DBAL\Connection |
| 51 | */ |
| 52 | public function __construct($dbalConnection) |
| 53 | { |
| 54 | $this->dbalPlatform = $dbalConnection->getDatabasePlatform(); |
| 55 | $this->dbalConnection = $dbalConnection; |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * @return \Doctrine\DBAL\Query\QueryBuilder |
| 60 | */ |
| 61 | public function getQueryBuilder() |
| 62 | { |
| 63 | return $this->dbalConnection->createQueryBuilder(); |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * Appends the correct LIMIT statement depending on the implementation of |
| 68 | * wrapper. For instance, limiting results in SQL statements are different |
| 69 | * mySQL and postgres. |
| 70 | * |
| 71 | * @access public |
| 72 | * @author Jerome Bogaerts, <jerome@taotesting.com> |
| 73 | * @param string $statement The statement to limit |
| 74 | * @param int $limit Limit lower bound. |
| 75 | * @param int $offset Limit upper bound. |
| 76 | * @return string |
| 77 | */ |
| 78 | public function limitStatement($statement, $limit, $offset = 0) |
| 79 | { |
| 80 | return $this->dbalPlatform->modifyLimitQuery($statement, $limit, $offset); |
| 81 | } |
| 82 | /** |
| 83 | * Dbal Text type returnedf stream in oracle this method handle others DBMS |
| 84 | * |
| 85 | * @param string $text |
| 86 | * @return string |
| 87 | */ |
| 88 | public function getPhpTextValue($text) |
| 89 | { |
| 90 | return $text; |
| 91 | } |
| 92 | |
| 93 | /** |
| 94 | * |
| 95 | * @author Lionel Lecaque, lionel@taotesting.com |
| 96 | * @return string |
| 97 | */ |
| 98 | public function getObjectTypeCondition() |
| 99 | { |
| 100 | return 'object '; |
| 101 | } |
| 102 | /** |
| 103 | * |
| 104 | * @return string |
| 105 | */ |
| 106 | public function getNullString() |
| 107 | { |
| 108 | return "''"; |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | * |
| 113 | * @param string $columnName |
| 114 | * @return string |
| 115 | */ |
| 116 | public function isNullCondition($columnName) |
| 117 | { |
| 118 | return $columnName . ' = ' . $this->getNullString(); |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 123 | * @param string $parameter |
| 124 | * @return string |
| 125 | */ |
| 126 | public function quoteIdentifier($parameter) |
| 127 | { |
| 128 | return $this->dbalPlatform->quoteIdentifier($parameter); |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 133 | * @param Schema $schema |
| 134 | * @return array |
| 135 | */ |
| 136 | public function schemaToSql($schema) |
| 137 | { |
| 138 | return $schema->toSql($this->dbalPlatform); |
| 139 | } |
| 140 | |
| 141 | /** |
| 142 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 143 | * @param Schema $schema |
| 144 | * @return array |
| 145 | */ |
| 146 | public function toDropSql($schema) |
| 147 | { |
| 148 | return $schema->toDropSql($this->dbalPlatform); |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 153 | * @param Schema $fromSchema |
| 154 | * @param Schema $toSchema |
| 155 | * @return array |
| 156 | */ |
| 157 | public function getMigrateSchemaSql($fromSchema, $toSchema) |
| 158 | { |
| 159 | return $fromSchema->getMigrateToSql($toSchema, $this->dbalPlatform); |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * Migrate Schema |
| 164 | * |
| 165 | * Migrate from $fromSchema to $toSchema. SQL queries to go from $fromSchema |
| 166 | * to $toSchema will be automatically executed. |
| 167 | * |
| 168 | * @param Schema $fromSchema |
| 169 | * @param Schema $toSchema |
| 170 | * @return int |
| 171 | * @throws DBALException |
| 172 | */ |
| 173 | public function migrateSchema(Schema $fromSchema, Schema $toSchema): int |
| 174 | { |
| 175 | $queryCount = 0; |
| 176 | |
| 177 | $queries = $this->getMigrateSchemaSql($fromSchema, $toSchema); |
| 178 | foreach ($queries as $query) { |
| 179 | $this->dbalConnection->exec($query); |
| 180 | $queryCount++; |
| 181 | } |
| 182 | |
| 183 | return $queryCount; |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Return driver name mysql, postgresql, oracle, mssql |
| 188 | * |
| 189 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 190 | */ |
| 191 | public function getName() |
| 192 | { |
| 193 | return $this->dbalPlatform->getName(); |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * @author Lionel Lecaque, lionel@taotesting.com |
| 198 | * @return string |
| 199 | */ |
| 200 | public function getNowExpression() |
| 201 | { |
| 202 | // We can't use $this->dbalPlatform->getNowExpression() because sqlite, |
| 203 | // at least used for the tests, returns `datetime('now')` which can |
| 204 | // not be parsed as a regular date. |
| 205 | // We instead generate a date with php and the format it with |
| 206 | // $this->dbalPlatform->getDateTimeTzFormatString(), to still have the |
| 207 | // correct format to be inserted in db. |
| 208 | |
| 209 | $datetime = new \DateTime('now', new \DateTimeZone('UTC')); |
| 210 | return $datetime->format($this->getDateTimeFormatString()); |
| 211 | } |
| 212 | |
| 213 | /** |
| 214 | * Returns platform specific date formatting with timezone to store datetime field. |
| 215 | * @return string |
| 216 | */ |
| 217 | public function getDateTimeFormatString() |
| 218 | { |
| 219 | return $this->dbalPlatform->getDateTimeFormatString(); |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Returns platform specific date formatting with timezone to store datetime field. |
| 224 | * @return string |
| 225 | */ |
| 226 | public function getDateTimeTzFormatString() |
| 227 | { |
| 228 | return $this->dbalPlatform->getDateTimeTzFormatString(); |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * |
| 233 | * @author "Lionel Lecaque, <lionel@taotesting.com>" |
| 234 | * @param string $functionName |
| 235 | * @return string |
| 236 | */ |
| 237 | public function getSqlFunction($functionName) |
| 238 | { |
| 239 | return "SELECT " . $functionName . '(?)'; |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows. |
| 244 | * |
| 245 | * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard. |
| 246 | * |
| 247 | * @see https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html |
| 248 | * @see https://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE |
| 249 | * @return string |
| 250 | */ |
| 251 | public function getWriteLockSQL() |
| 252 | { |
| 253 | return $this->dbalPlatform->getWriteLockSQL(); |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock. |
| 258 | * |
| 259 | * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database |
| 260 | * vendors allow to lighten this constraint up to be a real read lock. |
| 261 | * |
| 262 | * @return string |
| 263 | */ |
| 264 | public function getReadLockSQL() |
| 265 | { |
| 266 | return $this->dbalPlatform->getReadLockSQL(); |
| 267 | } |
| 268 | |
| 269 | /** |
| 270 | * Starts a transaction by suspending auto-commit mode. |
| 271 | * |
| 272 | * @return void |
| 273 | */ |
| 274 | public function beginTransaction() |
| 275 | { |
| 276 | $this->dbalConnection->beginTransaction(); |
| 277 | } |
| 278 | |
| 279 | /** |
| 280 | * Sets the transaction isolation level for the current connection. |
| 281 | * |
| 282 | * Transaction levels are: |
| 283 | * |
| 284 | * * common_persistence_sql_Platform::TRANSACTION_PLATFORM_DEFAULT |
| 285 | * * common_persistence_sql_Platform::TRANSACTION_READ_UNCOMMITTED |
| 286 | * * common_persistence_sql_Platform::TRANSACTION_READ_COMMITTED |
| 287 | * * common_persistence_sql_Platform::TRANSACTION_REPEATABLE_READ |
| 288 | * * common_persistence_sql_Platform::TRANSACTION_SERIALIZABLE |
| 289 | * |
| 290 | * IT IS EXTREMELY IMPORTANT than after calling commit() or rollback(), |
| 291 | * or in error handly, the developer sets back the initial transaction |
| 292 | * level that was in force prior the call to beginTransaction(). |
| 293 | * |
| 294 | * @param integer $level The level to set. |
| 295 | * |
| 296 | * @return integer |
| 297 | */ |
| 298 | public function setTransactionIsolation($level) |
| 299 | { |
| 300 | if ($level === self::TRANSACTION_PLATFORM_DEFAULT) { |
| 301 | $level = $this->dbalPlatform->getDefaultTransactionIsolationLevel(); |
| 302 | } |
| 303 | |
| 304 | $this->dbalConnection->setTransactionIsolation($level); |
| 305 | } |
| 306 | |
| 307 | /** |
| 308 | * Gets the currently active transaction isolation level for the current sesson. |
| 309 | * |
| 310 | * @return integer The current transaction isolation level for the current session. |
| 311 | */ |
| 312 | public function getTransactionIsolation() |
| 313 | { |
| 314 | return $this->dbalConnection->getTransactionIsolation(); |
| 315 | } |
| 316 | |
| 317 | /** |
| 318 | * Checks whether or not a transaction is currently active. |
| 319 | * |
| 320 | * @return boolean true if a transaction is currently active for the current session, otherwise false. |
| 321 | */ |
| 322 | public function isTransactionActive() |
| 323 | { |
| 324 | return $this->dbalConnection->isTransactionActive(); |
| 325 | } |
| 326 | |
| 327 | /** |
| 328 | * Cancels any database changes done during the current transaction. |
| 329 | * |
| 330 | * @throws \Doctrine\DBAL\ConnectionException If the rollback operation failed. |
| 331 | */ |
| 332 | public function rollBack() |
| 333 | { |
| 334 | $this->dbalConnection->rollBack(); |
| 335 | } |
| 336 | |
| 337 | /** |
| 338 | * Commits the current transaction. |
| 339 | * |
| 340 | * @return void |
| 341 | * @throws \Doctrine\DBAL\ConnectionException If the commit failed due to no active transaction or because the |
| 342 | * transaction was marked for rollback only. |
| 343 | * @throws DBALException |
| 344 | * @throws common_persistence_sql_SerializationException In case of SerializationFailure (SQLSTATE 40001). |
| 345 | */ |
| 346 | public function commit() |
| 347 | { |
| 348 | try { |
| 349 | $this->dbalConnection->commit(); |
| 350 | } catch (DBALException $e) { |
| 351 | // Surprisingly, DBAL's commit throws a PDOExeption in case |
| 352 | // of serialization issue (not documented). |
| 353 | if (($code = $e->getCode()) == '40001') { |
| 354 | // Serialization failure (SQLSTATE 40001 for at least mysql, pgsql, sqlsrv). |
| 355 | throw new common_persistence_sql_SerializationException( |
| 356 | "SQL Transaction Serialization Failure. See previous exception(s) for more information.", |
| 357 | intval($code), |
| 358 | $e |
| 359 | ); |
| 360 | } else { |
| 361 | // Another kind of error. Re-throw! |
| 362 | throw $e; |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | public function getTruncateTableSql($tableName) |
| 368 | { |
| 369 | return $this->dbalPlatform->getTruncateTableSql($tableName); |
| 370 | } |
| 371 | } |