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 | } |