|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Alpha\Model; |
|
4
|
|
|
|
|
5
|
|
|
use Alpha\Model\Type\Integer; |
|
6
|
|
|
use Alpha\Model\Type\Timestamp; |
|
7
|
|
|
use Alpha\Model\Type\DEnum; |
|
8
|
|
|
use Alpha\Model\Type\Relation; |
|
9
|
|
|
use Alpha\Model\Type\RelationLookup; |
|
10
|
|
|
use Alpha\Util\Config\ConfigProvider; |
|
11
|
|
|
use Alpha\Util\Logging\Logger; |
|
12
|
|
|
use Alpha\Util\Http\Session\SessionProviderFactory; |
|
13
|
|
|
use Alpha\Exception\AlphaException; |
|
14
|
|
|
use Alpha\Exception\FailedSaveException; |
|
15
|
|
|
use Alpha\Exception\FailedDeleteException; |
|
16
|
|
|
use Alpha\Exception\FailedIndexCreateException; |
|
17
|
|
|
use Alpha\Exception\LockingException; |
|
18
|
|
|
use Alpha\Exception\ValidationException; |
|
19
|
|
|
use Alpha\Exception\CustomQueryException; |
|
20
|
|
|
use Alpha\Exception\RecordNotFoundException; |
|
21
|
|
|
use Alpha\Exception\BadTableNameException; |
|
22
|
|
|
use Alpha\Exception\NotImplementedException; |
|
23
|
|
|
use Alpha\Exception\PHPException; |
|
24
|
|
|
use Exception; |
|
25
|
|
|
use SQLite3Stmt; |
|
26
|
|
|
use SQLite3; |
|
27
|
|
|
use ReflectionClass; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* SQLite active record provider (uses the SQLite3 native API in PHP). |
|
31
|
|
|
* |
|
32
|
|
|
* @since 1.2 |
|
33
|
|
|
* |
|
34
|
|
|
* @author John Collins <[email protected]> |
|
35
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License |
|
36
|
|
|
* @copyright Copyright (c) 2017, John Collins (founder of Alpha Framework). |
|
37
|
|
|
* All rights reserved. |
|
38
|
|
|
* |
|
39
|
|
|
* <pre> |
|
40
|
|
|
* Redistribution and use in source and binary forms, with or |
|
41
|
|
|
* without modification, are permitted provided that the |
|
42
|
|
|
* following conditions are met: |
|
43
|
|
|
* |
|
44
|
|
|
* * Redistributions of source code must retain the above |
|
45
|
|
|
* copyright notice, this list of conditions and the |
|
46
|
|
|
* following disclaimer. |
|
47
|
|
|
* * Redistributions in binary form must reproduce the above |
|
48
|
|
|
* copyright notice, this list of conditions and the |
|
49
|
|
|
* following disclaimer in the documentation and/or other |
|
50
|
|
|
* materials provided with the distribution. |
|
51
|
|
|
* * Neither the name of the Alpha Framework nor the names |
|
52
|
|
|
* of its contributors may be used to endorse or promote |
|
53
|
|
|
* products derived from this software without specific |
|
54
|
|
|
* prior written permission. |
|
55
|
|
|
* |
|
56
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
|
57
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
58
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
59
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
60
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
|
61
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
62
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
63
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
64
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
65
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
66
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
67
|
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
68
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
69
|
|
|
* </pre> |
|
70
|
|
|
*/ |
|
71
|
|
|
class ActiveRecordProviderSQLite implements ActiveRecordProviderInterface |
|
72
|
|
|
{ |
|
73
|
|
|
/** |
|
74
|
|
|
* Trace logger. |
|
75
|
|
|
* |
|
76
|
|
|
* @var \Alpha\Util\Logging\Logger |
|
77
|
|
|
* |
|
78
|
|
|
* @since 1.2 |
|
79
|
|
|
*/ |
|
80
|
|
|
private static $logger = null; |
|
81
|
|
|
|
|
82
|
|
|
/** |
|
83
|
|
|
* Database connection. |
|
84
|
|
|
* |
|
85
|
|
|
* @var SQLite3 |
|
86
|
|
|
* |
|
87
|
|
|
* @since 1.2 |
|
88
|
|
|
*/ |
|
89
|
|
|
private static $connection; |
|
90
|
|
|
|
|
91
|
|
|
/** |
|
92
|
|
|
* The business object that we are mapping back to. |
|
93
|
|
|
* |
|
94
|
|
|
* @var \Alpha\Model\ActiveRecord |
|
95
|
|
|
* |
|
96
|
|
|
* @since 1.2 |
|
97
|
|
|
*/ |
|
98
|
|
|
private $BO; |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* An array of new foreign keys that need to be created. |
|
102
|
|
|
* |
|
103
|
|
|
* @var array |
|
104
|
|
|
* |
|
105
|
|
|
* @since 2.0.1 |
|
106
|
|
|
*/ |
|
107
|
|
|
private $foreignKeys = array(); |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* The constructor. |
|
111
|
|
|
* |
|
112
|
|
|
* @since 1.2 |
|
113
|
|
|
*/ |
|
114
|
|
|
public function __construct() |
|
115
|
|
|
{ |
|
116
|
|
|
self::$logger = new Logger('ActiveRecordProviderSQLite'); |
|
117
|
|
|
self::$logger->debug('>>__construct()'); |
|
118
|
|
|
|
|
119
|
|
|
self::$logger->debug('<<__construct'); |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* (non-PHPdoc). |
|
124
|
|
|
* |
|
125
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getConnection() |
|
126
|
|
|
*/ |
|
127
|
|
|
public static function getConnection() |
|
128
|
|
|
{ |
|
129
|
|
|
$config = ConfigProvider::getInstance(); |
|
130
|
|
|
|
|
131
|
|
|
if (!isset(self::$connection)) { |
|
132
|
|
|
try { |
|
133
|
|
|
self::$connection = new SQLite3($config->get('db.file.path')); |
|
134
|
|
|
} catch (\Exception $e) { |
|
135
|
|
|
self::$logger->fatal('Could not open SQLite database: ['.$e->getMessage().']'); |
|
136
|
|
|
} |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
return self::$connection; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* (non-PHPdoc). |
|
144
|
|
|
* |
|
145
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::disconnect() |
|
146
|
|
|
*/ |
|
147
|
|
|
public static function disconnect() |
|
148
|
|
|
{ |
|
149
|
|
|
if (isset(self::$connection)) { |
|
150
|
|
|
self::$connection->close(); |
|
151
|
|
|
self::$connection = null; |
|
152
|
|
|
} |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* (non-PHPdoc). |
|
157
|
|
|
* |
|
158
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getLastDatabaseError() |
|
159
|
|
|
*/ |
|
160
|
|
|
public static function getLastDatabaseError() |
|
161
|
|
|
{ |
|
162
|
|
|
self::$connection->lastErrorMsg(); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* (non-PHPdoc). |
|
167
|
|
|
* |
|
168
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::query() |
|
169
|
|
|
*/ |
|
170
|
|
|
public function query($sqlQuery) |
|
171
|
|
|
{ |
|
172
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
173
|
|
|
|
|
174
|
|
|
$resultArray = array(); |
|
175
|
|
|
|
|
176
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
177
|
|
|
throw new CustomQueryException('Failed to run the custom query, SQLite error is ['.self::getLastDatabaseError().'], query ['.$sqlQuery.']'); |
|
178
|
|
|
} else { |
|
179
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
180
|
|
|
array_push($resultArray, $row); |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
return $resultArray; |
|
184
|
|
|
} |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
|
|
/** |
|
188
|
|
|
* (non-PHPdoc). |
|
189
|
|
|
* |
|
190
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::load() |
|
191
|
|
|
*/ |
|
192
|
|
|
public function load($OID, $version = 0) |
|
193
|
|
|
{ |
|
194
|
|
|
self::$logger->debug('>>load(OID=['.$OID.'], version=['.$version.'])'); |
|
195
|
|
|
|
|
196
|
|
|
$attributes = $this->BO->getPersistentAttributes(); |
|
197
|
|
|
$fields = ''; |
|
198
|
|
|
foreach ($attributes as $att) { |
|
199
|
|
|
$fields .= $att.','; |
|
200
|
|
|
} |
|
201
|
|
|
$fields = mb_substr($fields, 0, -1); |
|
202
|
|
|
|
|
203
|
|
View Code Duplication |
if ($version > 0) { |
|
|
|
|
|
|
204
|
|
|
$sqlQuery = 'SELECT '.$fields.' FROM '.$this->BO->getTableName().'_history WHERE OID = :OID AND version_num = :version LIMIT 1;'; |
|
205
|
|
|
} else { |
|
206
|
|
|
$sqlQuery = 'SELECT '.$fields.' FROM '.$this->BO->getTableName().' WHERE OID = :OID LIMIT 1;'; |
|
207
|
|
|
} |
|
208
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
209
|
|
|
|
|
210
|
|
|
try { |
|
211
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
212
|
|
|
|
|
213
|
|
|
$row = array(); |
|
214
|
|
|
|
|
215
|
|
|
if ($version > 0) { |
|
216
|
|
|
$stmt->bindValue(':version', $version, SQLITE3_INTEGER); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
$stmt->bindValue(':OID', $OID, SQLITE3_INTEGER); |
|
220
|
|
|
|
|
221
|
|
|
$result = $stmt->execute(); |
|
222
|
|
|
|
|
223
|
|
|
// there should only ever be one (or none) |
|
224
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
225
|
|
|
|
|
226
|
|
|
$stmt->close(); |
|
227
|
|
|
} catch (PHPException $e) { |
|
228
|
|
|
self::$logger->warn('The following query caused an unexpected result ['.$sqlQuery.']'); |
|
229
|
|
View Code Duplication |
if (!$this->BO->checkTableExists()) { |
|
|
|
|
|
|
230
|
|
|
$this->BO->makeTable(); |
|
231
|
|
|
|
|
232
|
|
|
throw new RecordNotFoundException('Failed to load object of OID ['.$OID.'], table ['.$this->BO->getTableName().'] did not exist so had to create!'); |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
|
|
return; |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
View Code Duplication |
if (!isset($row['OID']) || $row['OID'] < 1) { |
|
|
|
|
|
|
239
|
|
|
self::$logger->debug('<<load'); |
|
240
|
|
|
throw new RecordNotFoundException('Failed to load object of OID ['.$OID.'] not found in database.'); |
|
241
|
|
|
} |
|
242
|
|
|
|
|
243
|
|
|
// get the class attributes |
|
244
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
245
|
|
|
$properties = $reflection->getProperties(); |
|
246
|
|
|
|
|
247
|
|
|
try { |
|
248
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
249
|
|
|
$propName = $propObj->name; |
|
250
|
|
|
|
|
251
|
|
|
// filter transient attributes |
|
252
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
253
|
|
|
$this->BO->set($propName, $row[$propName]); |
|
254
|
|
|
} elseif (!$propObj->isPrivate() && $this->BO->getPropObject($propName) instanceof Relation) { |
|
255
|
|
|
$prop = $this->BO->getPropObject($propName); |
|
256
|
|
|
|
|
257
|
|
|
// handle the setting of ONE-TO-MANY relation values |
|
258
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY') { |
|
259
|
|
|
$this->BO->set($propObj->name, $this->BO->getOID()); |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
// handle the setting of MANY-TO-ONE relation values |
|
263
|
|
|
if ($prop->getRelationType() == 'MANY-TO-ONE' && isset($row[$propName])) { |
|
264
|
|
|
$this->BO->set($propObj->name, $row[$propName]); |
|
265
|
|
|
} |
|
266
|
|
|
} |
|
267
|
|
|
} |
|
268
|
|
|
} catch (IllegalArguementException $e) { |
|
|
|
|
|
|
269
|
|
|
self::$logger->warn('Bad data stored in the table ['.$this->BO->getTableName().'], field ['.$propObj->name.'] bad value['.$row[$propObj->name].'], exception ['.$e->getMessage().']'); |
|
270
|
|
|
} catch (PHPException $e) { |
|
271
|
|
|
// it is possible that the load failed due to the table not being up-to-date |
|
272
|
|
View Code Duplication |
if ($this->BO->checkTableNeedsUpdate()) { |
|
|
|
|
|
|
273
|
|
|
$missingFields = $this->BO->findMissingFields(); |
|
274
|
|
|
|
|
275
|
|
|
$count = count($missingFields); |
|
276
|
|
|
|
|
277
|
|
|
for ($i = 0; $i < $count; ++$i) { |
|
278
|
|
|
$this->BO->addProperty($missingFields[$i]); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
self::$logger->debug('<<load'); |
|
282
|
|
|
throw new RecordFoundException('Failed to load object of OID ['.$OID.'], table ['.$this->BO->getTableName().'] was out of sync with the database so had to be updated!'); |
|
283
|
|
|
} |
|
284
|
|
|
} |
|
285
|
|
|
|
|
286
|
|
|
self::$logger->debug('<<load'); |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
|
|
/** |
|
290
|
|
|
* (non-PHPdoc). |
|
291
|
|
|
* |
|
292
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAllOldVersions() |
|
293
|
|
|
*/ |
|
294
|
|
|
public function loadAllOldVersions($OID) |
|
295
|
|
|
{ |
|
296
|
|
|
self::$logger->debug('>>loadAllOldVersions(OID=['.$OID.'])'); |
|
297
|
|
|
|
|
298
|
|
|
if (!$this->BO->getMaintainHistory()) { |
|
299
|
|
|
throw new RecordFoundException('loadAllOldVersions method called on an active record where no history is maintained!'); |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
$sqlQuery = 'SELECT version_num FROM '.$this->BO->getTableName().'_history WHERE OID = \''.$OID.'\' ORDER BY version_num;'; |
|
303
|
|
|
|
|
304
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
305
|
|
|
|
|
306
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
307
|
|
|
self::$logger->debug('<<loadAllOldVersions'); |
|
308
|
|
|
throw new RecordNotFoundException('Failed to load object versions, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
// now build an array of objects to be returned |
|
312
|
|
|
$objects = array(); |
|
313
|
|
|
$count = 0; |
|
314
|
|
|
$RecordClass = get_class($this->BO); |
|
315
|
|
|
|
|
316
|
|
|
while ($row = $result->fetchArray()) { |
|
317
|
|
|
try { |
|
318
|
|
|
$obj = new $RecordClass(); |
|
319
|
|
|
$obj->load($OID, $row['version_num']); |
|
320
|
|
|
$objects[$count] = $obj; |
|
321
|
|
|
++$count; |
|
322
|
|
|
} catch (ResourceNotAllowedException $e) { |
|
|
|
|
|
|
323
|
|
|
// the resource not allowed will be absent from the list |
|
324
|
|
|
} |
|
325
|
|
|
} |
|
326
|
|
|
|
|
327
|
|
|
self::$logger->warn('<<loadAllOldVersions ['.count($objects).']'); |
|
328
|
|
|
|
|
329
|
|
|
return $objects; |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* (non-PHPdoc). |
|
334
|
|
|
* |
|
335
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadByAttribute() |
|
336
|
|
|
*/ |
|
337
|
|
|
public function loadByAttribute($attribute, $value, $ignoreClassType = false, $loadAttributes = array()) |
|
338
|
|
|
{ |
|
339
|
|
|
self::$logger->debug('>>loadByAttribute(attribute=['.$attribute.'], value=['.$value.'], ignoreClassType=['.$ignoreClassType.'], |
|
340
|
|
|
loadAttributes=['.var_export($loadAttributes, true).'])'); |
|
341
|
|
|
|
|
342
|
|
|
if (count($loadAttributes) == 0) { |
|
343
|
|
|
$attributes = $this->BO->getPersistentAttributes(); |
|
344
|
|
|
} else { |
|
345
|
|
|
$attributes = $loadAttributes; |
|
346
|
|
|
} |
|
347
|
|
|
|
|
348
|
|
|
$fields = ''; |
|
349
|
|
|
foreach ($attributes as $att) { |
|
350
|
|
|
$fields .= $att.','; |
|
351
|
|
|
} |
|
352
|
|
|
$fields = mb_substr($fields, 0, -1); |
|
353
|
|
|
|
|
354
|
|
View Code Duplication |
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
|
|
|
|
|
355
|
|
|
$sqlQuery = 'SELECT '.$fields.' FROM '.$this->BO->getTableName().' WHERE '.$attribute.' = :attribute AND classname = :classname LIMIT 1;'; |
|
356
|
|
|
} else { |
|
357
|
|
|
$sqlQuery = 'SELECT '.$fields.' FROM '.$this->BO->getTableName().' WHERE '.$attribute.' = :attribute LIMIT 1;'; |
|
358
|
|
|
} |
|
359
|
|
|
|
|
360
|
|
|
self::$logger->debug('Query=['.$sqlQuery.']'); |
|
361
|
|
|
|
|
362
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
363
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
364
|
|
|
|
|
365
|
|
|
$row = array(); |
|
|
|
|
|
|
366
|
|
|
|
|
367
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
368
|
|
|
if ($this->BO->getPropObject($attribute) instanceof Integer) { |
|
369
|
|
View Code Duplication |
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
|
|
|
|
|
370
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_INTEGER); |
|
371
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
372
|
|
|
} else { |
|
373
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_INTEGER); |
|
374
|
|
|
} |
|
375
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
376
|
|
|
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
377
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_TEXT); |
|
378
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
379
|
|
|
} else { |
|
380
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_TEXT); |
|
381
|
|
|
} |
|
382
|
|
|
} |
|
383
|
|
|
|
|
384
|
|
|
$result = $stmt->execute(); |
|
385
|
|
|
|
|
386
|
|
|
// there should only ever be one (or none) |
|
387
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
388
|
|
|
|
|
389
|
|
|
$stmt->close(); |
|
390
|
|
|
} else { |
|
391
|
|
|
self::$logger->warn('The following query caused an unexpected result ['.$sqlQuery.']'); |
|
392
|
|
|
if (!$this->BO->checkTableExists()) { |
|
393
|
|
|
$this->BO->makeTable(); |
|
394
|
|
|
|
|
395
|
|
|
throw new RecordNotFoundException('Failed to load object by attribute ['.$attribute.'] and value ['.$value.'], table did not exist so had to create!'); |
|
396
|
|
|
} |
|
397
|
|
|
|
|
398
|
|
|
return; |
|
399
|
|
|
} |
|
400
|
|
|
|
|
401
|
|
View Code Duplication |
if (!isset($row['OID']) || $row['OID'] < 1) { |
|
|
|
|
|
|
402
|
|
|
self::$logger->debug('<<loadByAttribute'); |
|
403
|
|
|
throw new RecordNotFoundException('Failed to load object by attribute ['.$attribute.'] and value ['.$value.'], not found in database.'); |
|
404
|
|
|
} |
|
405
|
|
|
|
|
406
|
|
|
$this->OID = $row['OID']; |
|
|
|
|
|
|
407
|
|
|
|
|
408
|
|
|
// get the class attributes |
|
409
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
410
|
|
|
$properties = $reflection->getProperties(); |
|
411
|
|
|
|
|
412
|
|
|
try { |
|
413
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
414
|
|
|
$propName = $propObj->name; |
|
415
|
|
|
|
|
416
|
|
|
if (isset($row[$propName])) { |
|
417
|
|
|
// filter transient attributes |
|
418
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
419
|
|
|
$this->BO->set($propName, $row[$propName]); |
|
420
|
|
|
} elseif (!$propObj->isPrivate() && $this->BO->get($propName) != '' && $this->BO->getPropObject($propName) instanceof Relation) { |
|
421
|
|
|
$prop = $this->BO->getPropObject($propName); |
|
422
|
|
|
|
|
423
|
|
|
// handle the setting of ONE-TO-MANY relation values |
|
424
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY') { |
|
425
|
|
|
$this->BO->set($propObj->name, $this->BO->getOID()); |
|
426
|
|
|
} |
|
427
|
|
|
} |
|
428
|
|
|
} |
|
429
|
|
|
} |
|
430
|
|
|
} catch (IllegalArguementException $e) { |
|
|
|
|
|
|
431
|
|
|
self::$logger->warn('Bad data stored in the table ['.$this->BO->getTableName().'], field ['.$propObj->name.'] bad value['.$row[$propObj->name].'], exception ['.$e->getMessage().']'); |
|
432
|
|
|
} catch (PHPException $e) { |
|
433
|
|
|
// it is possible that the load failed due to the table not being up-to-date |
|
434
|
|
View Code Duplication |
if ($this->BO->checkTableNeedsUpdate()) { |
|
|
|
|
|
|
435
|
|
|
$missingFields = $this->BO->findMissingFields(); |
|
436
|
|
|
|
|
437
|
|
|
$count = count($missingFields); |
|
438
|
|
|
|
|
439
|
|
|
for ($i = 0; $i < $count; ++$i) { |
|
440
|
|
|
$this->BO->addProperty($missingFields[$i]); |
|
441
|
|
|
} |
|
442
|
|
|
|
|
443
|
|
|
self::$logger->debug('<<loadByAttribute'); |
|
444
|
|
|
throw new RecordNotFoundException('Failed to load object by attribute ['.$attribute.'] and value ['.$value.'], table ['.$this->BO->getTableName().'] was out of sync with the database so had to be updated!'); |
|
445
|
|
|
} |
|
446
|
|
|
} |
|
447
|
|
|
|
|
448
|
|
|
self::$logger->debug('<<loadByAttribute'); |
|
449
|
|
|
} |
|
450
|
|
|
|
|
451
|
|
|
/** |
|
452
|
|
|
* (non-PHPdoc). |
|
453
|
|
|
* |
|
454
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAll() |
|
455
|
|
|
*/ |
|
456
|
|
View Code Duplication |
public function loadAll($start = 0, $limit = 0, $orderBy = 'OID', $order = 'ASC', $ignoreClassType = false) |
|
|
|
|
|
|
457
|
|
|
{ |
|
458
|
|
|
self::$logger->debug('>>loadAll(start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
|
459
|
|
|
|
|
460
|
|
|
// ensure that the field name provided in the orderBy param is legit |
|
461
|
|
|
try { |
|
462
|
|
|
$field = $this->BO->get($orderBy); |
|
|
|
|
|
|
463
|
|
|
} catch (AlphaException $e) { |
|
464
|
|
|
throw new AlphaException('The field name ['.$orderBy.'] provided in the param orderBy does not exist on the class ['.get_class($this->BO).']'); |
|
465
|
|
|
} |
|
466
|
|
|
|
|
467
|
|
|
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
468
|
|
|
if ($limit == 0) { |
|
469
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().' WHERE classname = \''.addslashes(get_class($this->BO)).'\' ORDER BY '.$orderBy.' '.$order.';'; |
|
470
|
|
|
} else { |
|
471
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().' WHERE classname = \''.addslashes(get_class($this->BO)).'\' ORDER BY '.$orderBy.' '.$order.' LIMIT '. |
|
472
|
|
|
$limit.' OFFSET '.$start.';'; |
|
473
|
|
|
} |
|
474
|
|
|
} else { |
|
475
|
|
|
if ($limit == 0) { |
|
476
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().' ORDER BY '.$orderBy.' '.$order.';'; |
|
477
|
|
|
} else { |
|
478
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().' ORDER BY '.$orderBy.' '.$order.' LIMIT '.$limit.' OFFSET '.$start.';'; |
|
479
|
|
|
} |
|
480
|
|
|
} |
|
481
|
|
|
|
|
482
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
483
|
|
|
|
|
484
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
485
|
|
|
self::$logger->debug('<<loadAll'); |
|
486
|
|
|
throw new RecordNotFoundException('Failed to load object OIDs, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
487
|
|
|
} |
|
488
|
|
|
|
|
489
|
|
|
// now build an array of objects to be returned |
|
490
|
|
|
$objects = array(); |
|
491
|
|
|
$count = 0; |
|
492
|
|
|
$RecordClass = get_class($this->BO); |
|
493
|
|
|
|
|
494
|
|
|
while ($row = $result->fetchArray()) { |
|
495
|
|
|
try { |
|
496
|
|
|
$obj = new $RecordClass(); |
|
497
|
|
|
$obj->load($row['OID']); |
|
498
|
|
|
$objects[$count] = $obj; |
|
499
|
|
|
++$count; |
|
500
|
|
|
} catch (ResourceNotAllowedException $e) { |
|
|
|
|
|
|
501
|
|
|
// the resource not allowed will be absent from the list |
|
502
|
|
|
} |
|
503
|
|
|
} |
|
504
|
|
|
|
|
505
|
|
|
self::$logger->debug('<<loadAll ['.count($objects).']'); |
|
506
|
|
|
|
|
507
|
|
|
return $objects; |
|
508
|
|
|
} |
|
509
|
|
|
|
|
510
|
|
|
/** |
|
511
|
|
|
* (non-PHPdoc). |
|
512
|
|
|
* |
|
513
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAllByAttribute() |
|
514
|
|
|
*/ |
|
515
|
|
|
public function loadAllByAttribute($attribute, $value, $start = 0, $limit = 0, $orderBy = 'OID', $order = 'ASC', $ignoreClassType = false, $constructorArgs = array()) |
|
516
|
|
|
{ |
|
517
|
|
|
self::$logger->debug('>>loadAllByAttribute(attribute=['.$attribute.'], value=['.$value.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']'); |
|
518
|
|
|
|
|
519
|
|
|
if ($start != 0 && $limit != 0) { |
|
520
|
|
|
$limit = ' LIMIT '.$limit.' OFFSET '.$start.';'; |
|
521
|
|
|
} else { |
|
522
|
|
|
$limit = ';'; |
|
523
|
|
|
} |
|
524
|
|
|
|
|
525
|
|
View Code Duplication |
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
|
|
|
|
|
526
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName()." WHERE $attribute = :attribute AND classname = :classname ORDER BY ".$orderBy.' '.$order.$limit; |
|
527
|
|
|
} else { |
|
528
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName()." WHERE $attribute = :attribute ORDER BY ".$orderBy.' '.$order.$limit; |
|
529
|
|
|
} |
|
530
|
|
|
|
|
531
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
532
|
|
|
self::$logger->debug($sqlQuery); |
|
533
|
|
|
|
|
534
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
535
|
|
|
|
|
536
|
|
|
$objects = array(); |
|
537
|
|
|
|
|
538
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
539
|
|
|
if ($this->BO->getPropObject($attribute) instanceof Integer) { |
|
540
|
|
View Code Duplication |
if ($this->BO->isTableOverloaded()) { |
|
|
|
|
|
|
541
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_INTEGER); |
|
542
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
543
|
|
|
} else { |
|
544
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_INTEGER); |
|
545
|
|
|
} |
|
546
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
547
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
548
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_TEXT); |
|
549
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
550
|
|
|
} else { |
|
551
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_TEXT); |
|
552
|
|
|
} |
|
553
|
|
|
} |
|
554
|
|
|
|
|
555
|
|
|
$result = $stmt->execute(); |
|
556
|
|
|
|
|
557
|
|
|
// now build an array of objects to be returned |
|
558
|
|
|
$count = 0; |
|
559
|
|
|
$RecordClass = get_class($this->BO); |
|
560
|
|
|
|
|
561
|
|
View Code Duplication |
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
|
|
|
|
|
562
|
|
|
try { |
|
563
|
|
|
$argsCount = count($constructorArgs); |
|
564
|
|
|
|
|
565
|
|
|
if ($argsCount < 1) { |
|
566
|
|
|
$obj = new $RecordClass(); |
|
567
|
|
|
} else { |
|
568
|
|
|
switch ($argsCount) { |
|
569
|
|
|
case 1: |
|
570
|
|
|
$obj = new $RecordClass($constructorArgs[0]); |
|
571
|
|
|
break; |
|
572
|
|
|
case 2: |
|
573
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1]); |
|
574
|
|
|
break; |
|
575
|
|
|
case 3: |
|
576
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2]); |
|
577
|
|
|
break; |
|
578
|
|
|
case 4: |
|
579
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2], $constructorArgs[3]); |
|
580
|
|
|
break; |
|
581
|
|
|
case 5: |
|
582
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2], $constructorArgs[3], $constructorArgs[4]); |
|
583
|
|
|
break; |
|
584
|
|
|
default: |
|
585
|
|
|
throw new IllegalArguementException('Too many elements in the $constructorArgs array passed to the loadAllByAttribute method!'); |
|
586
|
|
|
} |
|
587
|
|
|
} |
|
588
|
|
|
|
|
589
|
|
|
$obj->load($row['OID']); |
|
590
|
|
|
$objects[$count] = $obj; |
|
591
|
|
|
++$count; |
|
592
|
|
|
} catch (ResourceNotAllowedException $e) { |
|
|
|
|
|
|
593
|
|
|
// the resource not allowed will be absent from the list |
|
594
|
|
|
} |
|
595
|
|
|
} |
|
596
|
|
|
|
|
597
|
|
|
$stmt->close(); |
|
598
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
599
|
|
|
self::$logger->warn('The following query caused an unexpected result ['.$sqlQuery.']'); |
|
600
|
|
|
|
|
601
|
|
|
if (!$this->BO->checkTableExists()) { |
|
602
|
|
|
$this->BO->makeTable(); |
|
603
|
|
|
|
|
604
|
|
|
throw new RecordFoundException('Failed to load objects by attribute ['.$attribute.'] and value ['.$value.'], table did not exist so had to create!'); |
|
605
|
|
|
} |
|
606
|
|
|
|
|
607
|
|
|
self::$logger->debug('<<loadAllByAttribute []'); |
|
608
|
|
|
|
|
609
|
|
|
return array(); |
|
610
|
|
|
} |
|
611
|
|
|
|
|
612
|
|
|
self::$logger->debug('<<loadAllByAttribute ['.count($objects).']'); |
|
613
|
|
|
|
|
614
|
|
|
return $objects; |
|
615
|
|
|
} |
|
616
|
|
|
|
|
617
|
|
|
/** |
|
618
|
|
|
* (non-PHPdoc). |
|
619
|
|
|
* |
|
620
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAllByAttributes() |
|
621
|
|
|
*/ |
|
622
|
|
|
public function loadAllByAttributes($attributes = array(), $values = array(), $start = 0, $limit = 0, $orderBy = 'OID', $order = 'ASC', $ignoreClassType = false, $constructorArgs = array()) |
|
623
|
|
|
{ |
|
624
|
|
|
self::$logger->debug('>>loadAllByAttributes(attributes=['.var_export($attributes, true).'], values=['.var_export($values, true).'], start=['. |
|
625
|
|
|
$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']'); |
|
626
|
|
|
|
|
627
|
|
|
$whereClause = ' WHERE'; |
|
628
|
|
|
|
|
629
|
|
|
$count = count($attributes); |
|
630
|
|
|
|
|
631
|
|
|
for ($i = 0; $i < $count; ++$i) { |
|
632
|
|
|
$whereClause .= ' '.$attributes[$i].' = :'.$attributes[$i].' AND'; |
|
633
|
|
|
self::$logger->debug($whereClause); |
|
634
|
|
|
} |
|
635
|
|
|
|
|
636
|
|
|
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
637
|
|
|
$whereClause .= ' classname = :classname AND'; |
|
638
|
|
|
} |
|
639
|
|
|
|
|
640
|
|
|
// remove the last " AND" |
|
641
|
|
|
$whereClause = mb_substr($whereClause, 0, -4); |
|
642
|
|
|
|
|
643
|
|
|
if ($limit != 0) { |
|
644
|
|
|
$limit = ' LIMIT '.$limit.' OFFSET '.$start.';'; |
|
645
|
|
|
} else { |
|
646
|
|
|
$limit = ';'; |
|
647
|
|
|
} |
|
648
|
|
|
|
|
649
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().$whereClause.' ORDER BY '.$orderBy.' '.$order.$limit; |
|
650
|
|
|
|
|
651
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
652
|
|
|
|
|
653
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
654
|
|
|
|
|
655
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
656
|
|
|
// bind params where required attributes are provided |
|
657
|
|
|
if (count($attributes) > 0 && count($attributes) == count($values)) { |
|
658
|
|
|
for ($i = 0; $i < count($attributes); ++$i) { |
|
|
|
|
|
|
659
|
|
|
if (strcspn($values[$i], '0123456789') != strlen($values[$i])) { |
|
660
|
|
|
$stmt->bindValue(':'.$attributes[$i], $values[$i], SQLITE3_INTEGER); |
|
661
|
|
|
} else { |
|
662
|
|
|
$stmt->bindValue(':'.$attributes[$i], $values[$i], SQLITE3_TEXT); |
|
663
|
|
|
} |
|
664
|
|
|
} |
|
665
|
|
|
} else { |
|
666
|
|
|
// we'll still need to bind the "classname" for overloaded BOs... |
|
667
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
668
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
669
|
|
|
} |
|
670
|
|
|
} |
|
671
|
|
|
|
|
672
|
|
|
$result = $stmt->execute(); |
|
673
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
674
|
|
|
self::$logger->warn('The following query caused an unexpected result ['.$sqlQuery.']'); |
|
675
|
|
|
|
|
676
|
|
|
if (!$this->BO->checkTableExists()) { |
|
677
|
|
|
$this->BO->makeTable(); |
|
678
|
|
|
|
|
679
|
|
|
throw new RecordFoundException('Failed to load objects by attributes ['.var_export($attributes, true).'] and values ['. |
|
680
|
|
|
var_export($values, true).'], table did not exist so had to create!'); |
|
681
|
|
|
} |
|
682
|
|
|
|
|
683
|
|
|
self::$logger->debug('<<loadAllByAttributes []'); |
|
684
|
|
|
|
|
685
|
|
|
return array(); |
|
686
|
|
|
} |
|
687
|
|
|
|
|
688
|
|
|
// now build an array of objects to be returned |
|
689
|
|
|
$objects = array(); |
|
690
|
|
|
$count = 0; |
|
691
|
|
|
$RecordClass = get_class($this->BO); |
|
692
|
|
|
|
|
693
|
|
View Code Duplication |
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
|
|
|
|
|
694
|
|
|
try { |
|
695
|
|
|
$argsCount = count($constructorArgs); |
|
696
|
|
|
|
|
697
|
|
|
if ($argsCount < 1) { |
|
698
|
|
|
$obj = new $RecordClass(); |
|
699
|
|
|
} else { |
|
700
|
|
|
switch ($argsCount) { |
|
701
|
|
|
case 1: |
|
702
|
|
|
$obj = new $RecordClass($constructorArgs[0]); |
|
703
|
|
|
break; |
|
704
|
|
|
case 2: |
|
705
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1]); |
|
706
|
|
|
break; |
|
707
|
|
|
case 3: |
|
708
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2]); |
|
709
|
|
|
break; |
|
710
|
|
|
case 4: |
|
711
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2], $constructorArgs[3]); |
|
712
|
|
|
break; |
|
713
|
|
|
case 5: |
|
714
|
|
|
$obj = new $RecordClass($constructorArgs[0], $constructorArgs[1], $constructorArgs[2], $constructorArgs[3], $constructorArgs[4]); |
|
715
|
|
|
break; |
|
716
|
|
|
default: |
|
717
|
|
|
throw new IllegalArguementException('Too many elements in the $constructorArgs array passed to the loadAllByAttribute method!'); |
|
718
|
|
|
} |
|
719
|
|
|
} |
|
720
|
|
|
|
|
721
|
|
|
$obj->load($row['OID']); |
|
722
|
|
|
$objects[$count] = $obj; |
|
723
|
|
|
++$count; |
|
724
|
|
|
} catch (ResourceNotAllowedException $e) { |
|
|
|
|
|
|
725
|
|
|
// the resource not allowed will be absent from the list |
|
726
|
|
|
} |
|
727
|
|
|
} |
|
728
|
|
|
|
|
729
|
|
|
$stmt->close(); |
|
730
|
|
|
|
|
731
|
|
|
self::$logger->debug('<<loadAllByAttributes ['.count($objects).']'); |
|
732
|
|
|
|
|
733
|
|
|
return $objects; |
|
734
|
|
|
} |
|
735
|
|
|
|
|
736
|
|
|
/** |
|
737
|
|
|
* (non-PHPdoc). |
|
738
|
|
|
* |
|
739
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAllByDayUpdated() |
|
740
|
|
|
*/ |
|
741
|
|
View Code Duplication |
public function loadAllByDayUpdated($date, $start = 0, $limit = 0, $orderBy = 'OID', $order = 'ASC', $ignoreClassType = false) |
|
|
|
|
|
|
742
|
|
|
{ |
|
743
|
|
|
self::$logger->debug('>>loadAllByDayUpdated(date=['.$date.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
|
744
|
|
|
|
|
745
|
|
|
if ($start != 0 && $limit != 0) { |
|
746
|
|
|
$limit = ' LIMIT '.$limit.' OFFSET '.$start.';'; |
|
747
|
|
|
} else { |
|
748
|
|
|
$limit = ';'; |
|
749
|
|
|
} |
|
750
|
|
|
|
|
751
|
|
|
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
752
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName()." WHERE updated_ts >= '".$date." 00:00:00' AND updated_ts <= '".$date." 23:59:59' AND classname = '".addslashes(get_class($this->BO))."' ORDER BY ".$orderBy.' '.$order.$limit; |
|
753
|
|
|
} else { |
|
754
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName()." WHERE updated_ts >= '".$date." 00:00:00' AND updated_ts <= '".$date." 23:59:59' ORDER BY ".$orderBy.' '.$order.$limit; |
|
755
|
|
|
} |
|
756
|
|
|
|
|
757
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
758
|
|
|
|
|
759
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
760
|
|
|
self::$logger->debug('<<loadAllByDayUpdated'); |
|
761
|
|
|
throw new RecordNotFoundException('Failed to load object OIDs, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
762
|
|
|
} |
|
763
|
|
|
|
|
764
|
|
|
// now build an array of objects to be returned |
|
765
|
|
|
$objects = array(); |
|
766
|
|
|
$count = 0; |
|
767
|
|
|
$RecordClass = get_class($this->BO); |
|
768
|
|
|
|
|
769
|
|
|
while ($row = $result->fetchArray()) { |
|
770
|
|
|
$obj = new $RecordClass(); |
|
771
|
|
|
$obj->load($row['OID']); |
|
772
|
|
|
$objects[$count] = $obj; |
|
773
|
|
|
++$count; |
|
774
|
|
|
} |
|
775
|
|
|
|
|
776
|
|
|
self::$logger->debug('<<loadAllByDayUpdated ['.count($objects).']'); |
|
777
|
|
|
|
|
778
|
|
|
return $objects; |
|
779
|
|
|
} |
|
780
|
|
|
|
|
781
|
|
|
/** |
|
782
|
|
|
* (non-PHPdoc). |
|
783
|
|
|
* |
|
784
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::loadAllFieldValuesByAttribute() |
|
785
|
|
|
*/ |
|
786
|
|
|
public function loadAllFieldValuesByAttribute($attribute, $value, $returnAttribute, $order = 'ASC', $ignoreClassType = false) |
|
787
|
|
|
{ |
|
788
|
|
|
self::$logger->debug('>>loadAllFieldValuesByAttribute(attribute=['.$attribute.'], value=['.$value.'], returnAttribute=['.$returnAttribute.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
|
789
|
|
|
|
|
790
|
|
|
if (!$ignoreClassType && $this->BO->isTableOverloaded()) { |
|
791
|
|
|
$sqlQuery = 'SELECT '.$returnAttribute.' FROM '.$this->BO->getTableName()." WHERE $attribute = '$value' AND classname = '".addslashes(get_class($this->BO))."' ORDER BY OID ".$order.';'; |
|
792
|
|
|
} else { |
|
793
|
|
|
$sqlQuery = 'SELECT '.$returnAttribute.' FROM '.$this->BO->getTableName()." WHERE $attribute = '$value' ORDER BY OID ".$order.';'; |
|
794
|
|
|
} |
|
795
|
|
|
|
|
796
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
797
|
|
|
|
|
798
|
|
|
self::$logger->debug('lastQuery ['.$sqlQuery.']'); |
|
799
|
|
|
|
|
800
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
801
|
|
|
self::$logger->debug('<<loadAllFieldValuesByAttribute'); |
|
802
|
|
|
throw new RecordNotFoundException('Failed to load field ['.$returnAttribute.'] values, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
803
|
|
|
} |
|
804
|
|
|
|
|
805
|
|
|
// now build an array of attribute values to be returned |
|
806
|
|
|
$values = array(); |
|
807
|
|
|
$count = 0; |
|
808
|
|
|
$RecordClass = get_class($this->BO); |
|
|
|
|
|
|
809
|
|
|
|
|
810
|
|
|
while ($row = $result->fetchArray()) { |
|
811
|
|
|
$values[$count] = $row[$returnAttribute]; |
|
812
|
|
|
++$count; |
|
813
|
|
|
} |
|
814
|
|
|
|
|
815
|
|
|
self::$logger->debug('<<loadAllFieldValuesByAttribute ['.count($values).']'); |
|
816
|
|
|
|
|
817
|
|
|
return $values; |
|
818
|
|
|
} |
|
819
|
|
|
|
|
820
|
|
|
/** |
|
821
|
|
|
* (non-PHPdoc). |
|
822
|
|
|
* |
|
823
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::save() |
|
824
|
|
|
*/ |
|
825
|
|
|
public function save() |
|
826
|
|
|
{ |
|
827
|
|
|
self::$logger->debug('>>save()'); |
|
828
|
|
|
|
|
829
|
|
|
$config = ConfigProvider::getInstance(); |
|
830
|
|
|
$sessionProvider = $config->get('session.provider.name'); |
|
831
|
|
|
$session = SessionProviderFactory::getInstance($sessionProvider); |
|
832
|
|
|
|
|
833
|
|
|
// get the class attributes |
|
834
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
835
|
|
|
$properties = $reflection->getProperties(); |
|
836
|
|
|
|
|
837
|
|
|
if ($this->BO->getVersion() != $this->BO->getVersionNumber()->getValue()) { |
|
838
|
|
|
throw new LockingException('Could not save the object as it has been updated by another user. Please try saving again.'); |
|
839
|
|
|
} |
|
840
|
|
|
|
|
841
|
|
|
// set the "updated by" fields, we can only set the user id if someone is logged in |
|
842
|
|
|
if ($session->get('currentUser') != null) { |
|
843
|
|
|
$this->BO->set('updated_by', $session->get('currentUser')->getOID()); |
|
844
|
|
|
} |
|
845
|
|
|
|
|
846
|
|
|
$this->BO->set('updated_ts', new Timestamp(date('Y-m-d H:i:s'))); |
|
847
|
|
|
|
|
848
|
|
|
// check to see if it is a transient object that needs to be inserted |
|
849
|
|
|
if ($this->BO->isTransient()) { |
|
850
|
|
|
$savedFields = array(); |
|
851
|
|
|
$sqlQuery = 'INSERT INTO '.$this->BO->getTableName().' ('; |
|
852
|
|
|
|
|
853
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
854
|
|
|
$propName = $propObj->name; |
|
855
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
856
|
|
|
// Skip the OID, database auto number takes care of this. |
|
857
|
|
|
if ($propName != 'OID' && $propName != 'version_num') { |
|
858
|
|
|
$sqlQuery .= "$propName,"; |
|
859
|
|
|
$savedFields[] = $propName; |
|
860
|
|
|
} |
|
861
|
|
|
|
|
862
|
|
|
if ($propName == 'version_num') { |
|
863
|
|
|
$sqlQuery .= 'version_num,'; |
|
864
|
|
|
$savedFields[] = 'version_num'; |
|
865
|
|
|
} |
|
866
|
|
|
} |
|
867
|
|
|
} |
|
868
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
869
|
|
|
$sqlQuery .= 'classname,'; |
|
870
|
|
|
} |
|
871
|
|
|
|
|
872
|
|
|
$sqlQuery = rtrim($sqlQuery, ','); |
|
873
|
|
|
|
|
874
|
|
|
$sqlQuery .= ') VALUES ('; |
|
875
|
|
|
|
|
876
|
|
|
foreach ($savedFields as $savedField) { |
|
877
|
|
|
$sqlQuery .= ':'.$savedField.','; |
|
878
|
|
|
} |
|
879
|
|
|
|
|
880
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
881
|
|
|
$sqlQuery .= ':classname,'; |
|
882
|
|
|
} |
|
883
|
|
|
|
|
884
|
|
|
$sqlQuery = rtrim($sqlQuery, ',').')'; |
|
885
|
|
|
|
|
886
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
887
|
|
|
self::$logger->debug('Query ['.$sqlQuery.']'); |
|
888
|
|
|
|
|
889
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
890
|
|
|
|
|
891
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
892
|
|
View Code Duplication |
foreach ($savedFields as $savedField) { |
|
|
|
|
|
|
893
|
|
|
if ($this->BO->get($savedField) instanceof Integer) { |
|
894
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_INTEGER); |
|
895
|
|
|
} else { |
|
896
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_TEXT); |
|
897
|
|
|
} |
|
898
|
|
|
} |
|
899
|
|
|
|
|
900
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
901
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
902
|
|
|
} |
|
903
|
|
|
|
|
904
|
|
|
$stmt->bindValue(':version_num', 1, SQLITE3_INTEGER); // on an initial save, this will always be 1 |
|
905
|
|
|
$this->BO->set('version_num', 1); |
|
906
|
|
|
|
|
907
|
|
|
try { |
|
908
|
|
|
$stmt->execute(); |
|
909
|
|
|
} catch (Exception $e) { |
|
910
|
|
|
if (self::getConnection()->lastErrorCode() == 19) { |
|
911
|
|
|
throw new ValidationException('Unique key violation while trying to save object, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
912
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
913
|
|
|
throw new FailedSaveException('Failed to save object, exception ['.$e->getMessage().'], DB error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
914
|
|
|
} |
|
915
|
|
|
} |
|
916
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
917
|
|
|
throw new FailedSaveException('Failed to save object, exception ['.$e->getMessage().'], DB error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
918
|
|
|
} |
|
919
|
|
|
} else { |
|
920
|
|
|
// assume that it is a persistent object that needs to be updated |
|
921
|
|
|
$savedFields = array(); |
|
922
|
|
|
$sqlQuery = 'UPDATE '.$this->BO->getTableName().' SET '; |
|
923
|
|
|
|
|
924
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
925
|
|
|
$propName = $propObj->name; |
|
926
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
927
|
|
|
// Skip the OID, database auto number takes care of this. |
|
928
|
|
|
if ($propName != 'OID' && $propName != 'version_num') { |
|
929
|
|
|
$sqlQuery .= "$propName = :$propName,"; |
|
930
|
|
|
$savedFields[] = $propName; |
|
931
|
|
|
} |
|
932
|
|
|
|
|
933
|
|
|
if ($propName == 'version_num') { |
|
934
|
|
|
$sqlQuery .= 'version_num = :version_num,'; |
|
935
|
|
|
$savedFields[] = 'version_num'; |
|
936
|
|
|
} |
|
937
|
|
|
} |
|
938
|
|
|
} |
|
939
|
|
|
|
|
940
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
941
|
|
|
$sqlQuery .= 'classname = :classname,'; |
|
942
|
|
|
} |
|
943
|
|
|
|
|
944
|
|
|
$sqlQuery = rtrim($sqlQuery, ','); |
|
945
|
|
|
|
|
946
|
|
|
$sqlQuery .= ' WHERE OID=:OID;'; |
|
947
|
|
|
|
|
948
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
949
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
950
|
|
|
|
|
951
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
952
|
|
View Code Duplication |
foreach ($savedFields as $savedField) { |
|
|
|
|
|
|
953
|
|
|
if ($this->BO->get($savedField) instanceof Integer) { |
|
954
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_INTEGER); |
|
955
|
|
|
} else { |
|
956
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_TEXT); |
|
957
|
|
|
} |
|
958
|
|
|
} |
|
959
|
|
|
|
|
960
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
961
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
962
|
|
|
} |
|
963
|
|
|
|
|
964
|
|
|
$stmt->bindValue(':OID', $this->BO->getOID(), SQLITE3_INTEGER); |
|
965
|
|
|
|
|
966
|
|
|
$temp = $this->BO->getVersionNumber()->getValue(); |
|
967
|
|
|
$this->BO->set('version_num', $temp + 1); |
|
968
|
|
|
$stmt->bindValue(':version_num', $temp + 1, SQLITE3_INTEGER); |
|
969
|
|
|
|
|
970
|
|
|
$stmt->execute(); |
|
971
|
|
|
} else { |
|
972
|
|
|
throw new FailedSaveException('Failed to save object, error is ['.$stmt->error.'], query ['.$this->BO->getLastQuery().']'); |
|
973
|
|
|
} |
|
974
|
|
|
} |
|
975
|
|
|
|
|
976
|
|
|
if ($stmt != null && $stmt != false) { |
|
977
|
|
|
// populate the updated OID in case we just done an insert |
|
978
|
|
|
if ($this->BO->isTransient()) { |
|
979
|
|
|
$this->BO->setOID(self::getConnection()->lastInsertRowID()); |
|
980
|
|
|
} |
|
981
|
|
|
|
|
982
|
|
|
try { |
|
983
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
984
|
|
|
$propName = $propObj->name; |
|
985
|
|
|
|
|
986
|
|
|
if ($this->BO->getPropObject($propName) instanceof Relation) { |
|
987
|
|
|
$prop = $this->BO->getPropObject($propName); |
|
988
|
|
|
|
|
989
|
|
|
// handle the saving of MANY-TO-MANY relation values |
|
990
|
|
|
if ($prop->getRelationType() == 'MANY-TO-MANY' && count($prop->getRelatedOIDs()) > 0) { |
|
991
|
|
|
try { |
|
992
|
|
|
try { |
|
993
|
|
|
// check to see if the rel is on this class |
|
994
|
|
|
$side = $prop->getSide(get_class($this->BO)); |
|
995
|
|
|
} catch (IllegalArguementException $iae) { |
|
|
|
|
|
|
996
|
|
|
$side = $prop->getSide(get_parent_class($this->BO)); |
|
997
|
|
|
} |
|
998
|
|
|
|
|
999
|
|
|
$lookUp = $prop->getLookup(); |
|
1000
|
|
|
|
|
1001
|
|
|
// first delete all of the old RelationLookup objects for this rel |
|
1002
|
|
|
try { |
|
1003
|
|
|
if ($side == 'left') { |
|
1004
|
|
|
$lookUp->deleteAllByAttribute('leftID', $this->BO->getOID()); |
|
1005
|
|
|
} else { |
|
1006
|
|
|
$lookUp->deleteAllByAttribute('rightID', $this->BO->getOID()); |
|
1007
|
|
|
} |
|
1008
|
|
|
} catch (Exception $e) { |
|
1009
|
|
|
throw new FailedSaveException('Failed to delete old RelationLookup objects on the table ['.$prop->getLookup()->getTableName().'], error is ['.$e->getMessage().']'); |
|
1010
|
|
|
} |
|
1011
|
|
|
|
|
1012
|
|
|
$OIDs = $prop->getRelatedOIDs(); |
|
1013
|
|
|
|
|
1014
|
|
|
if (isset($OIDs) && !empty($OIDs[0])) { |
|
1015
|
|
|
// now for each posted OID, create a new RelationLookup record and save |
|
1016
|
|
|
foreach ($OIDs as $oid) { |
|
1017
|
|
|
$newLookUp = new RelationLookup($lookUp->get('leftClassName'), $lookUp->get('rightClassName')); |
|
1018
|
|
|
if ($side == 'left') { |
|
1019
|
|
|
$newLookUp->set('leftID', $this->BO->getOID()); |
|
1020
|
|
|
$newLookUp->set('rightID', $oid); |
|
1021
|
|
|
} else { |
|
1022
|
|
|
$newLookUp->set('rightID', $this->BO->getOID()); |
|
1023
|
|
|
$newLookUp->set('leftID', $oid); |
|
1024
|
|
|
} |
|
1025
|
|
|
$newLookUp->save(); |
|
1026
|
|
|
} |
|
1027
|
|
|
} |
|
1028
|
|
|
} catch (Exception $e) { |
|
1029
|
|
|
throw new FailedSaveException('Failed to update a MANY-TO-MANY relation on the object, error is ['.$e->getMessage().']'); |
|
1030
|
|
|
|
|
1031
|
|
|
return; |
|
|
|
|
|
|
1032
|
|
|
} |
|
1033
|
|
|
} |
|
1034
|
|
|
|
|
1035
|
|
|
// handle the saving of ONE-TO-MANY relation values |
|
1036
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY') { |
|
1037
|
|
|
$prop->setValue($this->BO->getOID()); |
|
1038
|
|
|
} |
|
1039
|
|
|
} |
|
1040
|
|
|
} |
|
1041
|
|
|
} catch (Exception $e) { |
|
1042
|
|
|
throw new FailedSaveException('Failed to save object, error is ['.$e->getMessage().']'); |
|
1043
|
|
|
} |
|
1044
|
|
|
|
|
1045
|
|
|
$stmt->close(); |
|
1046
|
|
|
} else { |
|
1047
|
|
|
// there has been an error, so decrement the version number back |
|
1048
|
|
|
$temp = $this->BO->getVersionNumber()->getValue(); |
|
1049
|
|
|
$this->BO->set('version_num', $temp - 1); |
|
1050
|
|
|
|
|
1051
|
|
|
throw new FailedSaveException('Failed to save object, SQLite error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
1052
|
|
|
} |
|
1053
|
|
|
|
|
1054
|
|
|
if ($this->BO->getMaintainHistory()) { |
|
1055
|
|
|
$this->BO->saveHistory(); |
|
1056
|
|
|
} |
|
1057
|
|
|
} |
|
1058
|
|
|
|
|
1059
|
|
|
/** |
|
1060
|
|
|
* (non-PHPdoc). |
|
1061
|
|
|
* |
|
1062
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::saveAttribute() |
|
1063
|
|
|
*/ |
|
1064
|
|
|
public function saveAttribute($attribute, $value) |
|
1065
|
|
|
{ |
|
1066
|
|
|
self::$logger->debug('>>saveAttribute(attribute=['.$attribute.'], value=['.$value.'])'); |
|
1067
|
|
|
|
|
1068
|
|
|
// assume that it is a persistent object that needs to be updated |
|
1069
|
|
|
$sqlQuery = 'UPDATE '.$this->BO->getTableName().' SET '.$attribute.'=:attribute, version_num =:version WHERE OID=:OID;'; |
|
1070
|
|
|
|
|
1071
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1072
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
1073
|
|
|
|
|
1074
|
|
|
$newVersionNumber = $this->BO->getVersionNumber()->getValue() + 1; |
|
1075
|
|
|
|
|
1076
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
1077
|
|
|
if ($this->BO->getPropObject($attribute) instanceof Integer) { |
|
1078
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_INTEGER); |
|
1079
|
|
|
} else { |
|
1080
|
|
|
$stmt->bindValue(':attribute', $value, SQLITE3_TEXT); |
|
1081
|
|
|
} |
|
1082
|
|
|
|
|
1083
|
|
|
$stmt->bindValue(':version', $newVersionNumber, SQLITE3_INTEGER); |
|
1084
|
|
|
$stmt->bindValue(':OID', $this->BO->getOID(), SQLITE3_INTEGER); |
|
1085
|
|
|
|
|
1086
|
|
|
$stmt->execute(); |
|
1087
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
1088
|
|
|
throw new FailedSaveException('Failed to save attribute, error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
1089
|
|
|
} |
|
1090
|
|
|
|
|
1091
|
|
|
$stmt->close(); |
|
1092
|
|
|
|
|
1093
|
|
|
$this->BO->set($attribute, $value); |
|
1094
|
|
|
$this->BO->set('version_num', $newVersionNumber); |
|
1095
|
|
|
|
|
1096
|
|
|
if ($this->BO->getMaintainHistory()) { |
|
1097
|
|
|
$this->BO->saveHistory(); |
|
1098
|
|
|
} |
|
1099
|
|
|
|
|
1100
|
|
|
self::$logger->debug('<<saveAttribute'); |
|
1101
|
|
|
} |
|
1102
|
|
|
|
|
1103
|
|
|
/** |
|
1104
|
|
|
* (non-PHPdoc). |
|
1105
|
|
|
* |
|
1106
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::saveHistory() |
|
1107
|
|
|
*/ |
|
1108
|
|
|
public function saveHistory() |
|
1109
|
|
|
{ |
|
1110
|
|
|
self::$logger->debug('>>saveHistory()'); |
|
1111
|
|
|
|
|
1112
|
|
|
// get the class attributes |
|
1113
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
1114
|
|
|
$properties = $reflection->getProperties(); |
|
1115
|
|
|
|
|
1116
|
|
|
$savedFields = array(); |
|
1117
|
|
|
$attributeNames = array(); |
|
1118
|
|
|
$attributeValues = array(); |
|
1119
|
|
|
|
|
1120
|
|
|
$sqlQuery = 'INSERT INTO '.$this->BO->getTableName().'_history ('; |
|
1121
|
|
|
|
|
1122
|
|
View Code Duplication |
foreach ($properties as $propObj) { |
|
|
|
|
|
|
1123
|
|
|
$propName = $propObj->name; |
|
1124
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
1125
|
|
|
$sqlQuery .= "$propName,"; |
|
1126
|
|
|
$attributeNames[] = $propName; |
|
1127
|
|
|
$attributeValues[] = $this->BO->get($propName); |
|
1128
|
|
|
$savedFields[] = $propName; |
|
1129
|
|
|
} |
|
1130
|
|
|
} |
|
1131
|
|
|
|
|
1132
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1133
|
|
|
$sqlQuery .= 'classname,'; |
|
1134
|
|
|
} |
|
1135
|
|
|
|
|
1136
|
|
|
$sqlQuery = rtrim($sqlQuery, ','); |
|
1137
|
|
|
|
|
1138
|
|
|
$sqlQuery .= ') VALUES ('; |
|
1139
|
|
|
|
|
1140
|
|
|
foreach ($savedFields as $savedField) { |
|
1141
|
|
|
$sqlQuery .= ':'.$savedField.','; |
|
1142
|
|
|
} |
|
1143
|
|
|
|
|
1144
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1145
|
|
|
$sqlQuery .= ':classname,'; |
|
1146
|
|
|
} |
|
1147
|
|
|
|
|
1148
|
|
|
$sqlQuery = rtrim($sqlQuery, ',').')'; |
|
1149
|
|
|
|
|
1150
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1151
|
|
|
self::$logger->debug('Query ['.$sqlQuery.']'); |
|
1152
|
|
|
|
|
1153
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
1154
|
|
|
|
|
1155
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
1156
|
|
View Code Duplication |
foreach ($savedFields as $savedField) { |
|
|
|
|
|
|
1157
|
|
|
if ($this->BO->get($savedField) instanceof Integer) { |
|
1158
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_INTEGER); |
|
1159
|
|
|
} else { |
|
1160
|
|
|
$stmt->bindValue(':'.$savedField, $this->BO->get($savedField), SQLITE3_TEXT); |
|
1161
|
|
|
} |
|
1162
|
|
|
} |
|
1163
|
|
|
|
|
1164
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1165
|
|
|
$stmt->bindValue(':classname', get_class($this->BO), SQLITE3_TEXT); |
|
1166
|
|
|
} |
|
1167
|
|
|
|
|
1168
|
|
|
$stmt->execute(); |
|
1169
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
1170
|
|
|
throw new FailedSaveException('Failed to save object history, error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
1171
|
|
|
} |
|
1172
|
|
|
} |
|
1173
|
|
|
|
|
1174
|
|
|
/** |
|
1175
|
|
|
* (non-PHPdoc). |
|
1176
|
|
|
* |
|
1177
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::delete() |
|
1178
|
|
|
*/ |
|
1179
|
|
|
public function delete() |
|
1180
|
|
|
{ |
|
1181
|
|
|
self::$logger->debug('>>delete()'); |
|
1182
|
|
|
|
|
1183
|
|
|
$sqlQuery = 'DELETE FROM '.$this->BO->getTableName().' WHERE OID = :OID;'; |
|
1184
|
|
|
|
|
1185
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1186
|
|
|
|
|
1187
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
1188
|
|
|
|
|
1189
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
1190
|
|
|
$stmt->bindValue(':OID', $this->BO->getOID(), SQLITE3_INTEGER); |
|
1191
|
|
|
$stmt->execute(); |
|
1192
|
|
|
self::$logger->debug('Deleted the object ['.$this->BO->getOID().'] of class ['.get_class($this->BO).']'); |
|
1193
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
1194
|
|
|
throw new FailedDeleteException('Failed to delete object ['.$this->BO->getOID().'], error is ['.self::getLastDatabaseError().'], query ['.$this->BO->getLastQuery().']'); |
|
1195
|
|
|
} |
|
1196
|
|
|
|
|
1197
|
|
|
$stmt->close(); |
|
1198
|
|
|
|
|
1199
|
|
|
self::$logger->debug('<<delete'); |
|
1200
|
|
|
} |
|
1201
|
|
|
|
|
1202
|
|
|
/** |
|
1203
|
|
|
* (non-PHPdoc). |
|
1204
|
|
|
* |
|
1205
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getVersion() |
|
1206
|
|
|
*/ |
|
1207
|
|
|
public function getVersion() |
|
1208
|
|
|
{ |
|
1209
|
|
|
self::$logger->debug('>>getVersion()'); |
|
1210
|
|
|
|
|
1211
|
|
|
$sqlQuery = 'SELECT version_num FROM '.$this->BO->getTableName().' WHERE OID = :OID;'; |
|
1212
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1213
|
|
|
|
|
1214
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
1215
|
|
|
|
|
1216
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
1217
|
|
|
$stmt->bindValue(':OID', $this->BO->getOID(), SQLITE3_INTEGER); |
|
1218
|
|
|
|
|
1219
|
|
|
$result = $stmt->execute(); |
|
1220
|
|
|
|
|
1221
|
|
|
// there should only ever be one (or none) |
|
1222
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
1223
|
|
|
|
|
1224
|
|
|
$stmt->close(); |
|
1225
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
1226
|
|
|
self::$logger->warn('The following query caused an unexpected result ['.$sqlQuery.']'); |
|
1227
|
|
|
if (!$this->BO->checkTableExists()) { |
|
1228
|
|
|
$this->BO->makeTable(); |
|
1229
|
|
|
|
|
1230
|
|
|
throw new RecordNotFoundException('Failed to get the version number, table did not exist so had to create!'); |
|
1231
|
|
|
} |
|
1232
|
|
|
|
|
1233
|
|
|
return; |
|
1234
|
|
|
} |
|
1235
|
|
|
|
|
1236
|
|
View Code Duplication |
if (!isset($row['version_num']) || $row['version_num'] < 1) { |
|
|
|
|
|
|
1237
|
|
|
self::$logger->debug('<<getVersion [0]'); |
|
1238
|
|
|
|
|
1239
|
|
|
return 0; |
|
1240
|
|
|
} else { |
|
1241
|
|
|
$version_num = $row['version_num']; |
|
1242
|
|
|
|
|
1243
|
|
|
self::$logger->debug('<<getVersion ['.$version_num.']'); |
|
1244
|
|
|
|
|
1245
|
|
|
return $version_num; |
|
1246
|
|
|
} |
|
1247
|
|
|
} |
|
1248
|
|
|
|
|
1249
|
|
|
/** |
|
1250
|
|
|
* (non-PHPdoc). |
|
1251
|
|
|
* |
|
1252
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::makeTable() |
|
1253
|
|
|
*/ |
|
1254
|
|
|
public function makeTable() |
|
1255
|
|
|
{ |
|
1256
|
|
|
self::$logger->debug('>>makeTable()'); |
|
1257
|
|
|
|
|
1258
|
|
|
$sqlQuery = 'CREATE TABLE '.$this->BO->getTableName().' (OID INTEGER PRIMARY KEY,'; |
|
1259
|
|
|
|
|
1260
|
|
|
// get the class attributes |
|
1261
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
1262
|
|
|
$properties = $reflection->getProperties(); |
|
1263
|
|
|
|
|
1264
|
|
|
$foreignKeys = array(); |
|
1265
|
|
|
|
|
1266
|
|
|
foreach ($properties as $propObj) { |
|
1267
|
|
|
$propName = $propObj->name; |
|
1268
|
|
|
|
|
1269
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes()) && $propName != 'OID') { |
|
1270
|
|
|
$propReflect = new ReflectionClass($this->BO->getPropObject($propName)); |
|
1271
|
|
|
$propClass = $propReflect->getShortName(); |
|
1272
|
|
|
|
|
1273
|
|
|
switch (mb_strtoupper($propClass)) { |
|
1274
|
|
|
case 'INTEGER': |
|
1275
|
|
|
// special properties for RelationLookup OIDs |
|
1276
|
|
|
if ($this->BO instanceof RelationLookup && ($propName == 'leftID' || $propName == 'rightID')) { |
|
1277
|
|
|
$sqlQuery .= "$propName INTEGER(".$this->BO->getPropObject($propName)->getSize().') NOT NULL,'; |
|
|
|
|
|
|
1278
|
|
|
} else { |
|
1279
|
|
|
$sqlQuery .= "$propName INTEGER(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1280
|
|
|
} |
|
1281
|
|
|
break; |
|
1282
|
|
|
case 'DOUBLE': |
|
1283
|
|
|
$sqlQuery .= "$propName REAL(".$this->BO->getPropObject($propName)->getSize(true).'),'; |
|
|
|
|
|
|
1284
|
|
|
break; |
|
1285
|
|
|
case 'SMALLTEXT': |
|
1286
|
|
|
$sqlQuery .= "$propName TEXT(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1287
|
|
|
break; |
|
1288
|
|
|
case 'TEXT': |
|
1289
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1290
|
|
|
break; |
|
1291
|
|
|
case 'BOOLEAN': |
|
1292
|
|
|
$sqlQuery .= "$propName INTEGER(1) DEFAULT '0',"; |
|
1293
|
|
|
break; |
|
1294
|
|
|
case 'DATE': |
|
1295
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1296
|
|
|
break; |
|
1297
|
|
|
case 'TIMESTAMP': |
|
1298
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1299
|
|
|
break; |
|
1300
|
|
|
case 'ENUM': |
|
1301
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1302
|
|
|
break; |
|
1303
|
|
|
case 'DENUM': |
|
1304
|
|
|
$tmp = new DEnum(get_class($this->BO).'::'.$propName); |
|
|
|
|
|
|
1305
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1306
|
|
|
break; |
|
1307
|
|
|
case 'RELATION': |
|
1308
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1309
|
|
|
|
|
1310
|
|
|
$rel = $this->BO->getPropObject($propName); |
|
1311
|
|
|
|
|
1312
|
|
|
$relatedField = $rel->getRelatedClassField(); |
|
1313
|
|
|
$relatedClass = $rel->getRelatedClass(); |
|
1314
|
|
|
$relatedBO = new $relatedClass(); |
|
1315
|
|
|
$tableName = $relatedBO->getTableName(); |
|
1316
|
|
|
$foreignKeys[$propName] = array($tableName, $relatedField); |
|
1317
|
|
|
break; |
|
1318
|
|
|
default: |
|
1319
|
|
|
$sqlQuery .= ''; |
|
1320
|
|
|
break; |
|
1321
|
|
|
} |
|
1322
|
|
|
} |
|
1323
|
|
|
} |
|
1324
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1325
|
|
|
$sqlQuery .= 'classname TEXT(100)'; |
|
1326
|
|
|
} else { |
|
1327
|
|
|
$sqlQuery = mb_substr($sqlQuery, 0, -1); |
|
1328
|
|
|
} |
|
1329
|
|
|
|
|
1330
|
|
|
if (count($foreignKeys) > 0) { |
|
1331
|
|
View Code Duplication |
foreach ($foreignKeys as $field => $related) { |
|
|
|
|
|
|
1332
|
|
|
$sqlQuery .= ', FOREIGN KEY ('.$field.') REFERENCES '.$related[0].'('.$related[1].')'; |
|
1333
|
|
|
} |
|
1334
|
|
|
} |
|
1335
|
|
|
|
|
1336
|
|
|
if (count($this->foreignKeys) > 0) { |
|
1337
|
|
View Code Duplication |
foreach ($this->foreignKeys as $field => $related) { |
|
|
|
|
|
|
1338
|
|
|
$sqlQuery .= ', FOREIGN KEY ('.$field.') REFERENCES '.$related[0].'('.$related[1].')'; |
|
1339
|
|
|
} |
|
1340
|
|
|
} |
|
1341
|
|
|
|
|
1342
|
|
|
$sqlQuery .= ');'; |
|
1343
|
|
|
|
|
1344
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1345
|
|
|
|
|
1346
|
|
|
if (!self::getConnection()->exec($sqlQuery)) { |
|
1347
|
|
|
self::$logger->debug('<<makeTable'); |
|
1348
|
|
|
throw new AlphaException('Failed to create the table ['.$this->BO->getTableName().'] for the class ['.get_class($this->BO).'], database error is ['.self::getLastDatabaseError().']'); |
|
1349
|
|
|
} |
|
1350
|
|
|
|
|
1351
|
|
|
// check the table indexes if any additional ones required |
|
1352
|
|
|
$this->checkIndexes(); |
|
1353
|
|
|
|
|
1354
|
|
|
if ($this->BO->getMaintainHistory()) { |
|
1355
|
|
|
$this->BO->makeHistoryTable(); |
|
1356
|
|
|
} |
|
1357
|
|
|
|
|
1358
|
|
|
self::$logger->debug('<<makeTable'); |
|
1359
|
|
|
} |
|
1360
|
|
|
|
|
1361
|
|
|
/** |
|
1362
|
|
|
* (non-PHPdoc). |
|
1363
|
|
|
* |
|
1364
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::makeHistoryTable() |
|
1365
|
|
|
*/ |
|
1366
|
|
|
public function makeHistoryTable() |
|
1367
|
|
|
{ |
|
1368
|
|
|
self::$logger->debug('>>makeHistoryTable()'); |
|
1369
|
|
|
|
|
1370
|
|
|
$sqlQuery = 'CREATE TABLE '.$this->BO->getTableName().'_history (OID INTEGER NOT NULL,'; |
|
1371
|
|
|
|
|
1372
|
|
|
// get the class attributes |
|
1373
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
1374
|
|
|
$properties = $reflection->getProperties(); |
|
1375
|
|
|
|
|
1376
|
|
|
foreach ($properties as $propObj) { |
|
1377
|
|
|
$propName = $propObj->name; |
|
1378
|
|
|
|
|
1379
|
|
View Code Duplication |
if (!in_array($propName, $this->BO->getTransientAttributes()) && $propName != 'OID') { |
|
|
|
|
|
|
1380
|
|
|
$propReflect = new ReflectionClass($this->BO->getPropObject($propName)); |
|
1381
|
|
|
$propClass = $propReflect->getShortName(); |
|
1382
|
|
|
|
|
1383
|
|
|
switch (mb_strtoupper($propClass)) { |
|
1384
|
|
|
case 'INTEGER': |
|
1385
|
|
|
// special properties for RelationLookup OIDs |
|
1386
|
|
|
if ($this->BO instanceof RelationLookup && ($propName == 'leftID' || $propName == 'rightID')) { |
|
1387
|
|
|
$sqlQuery .= "$propName INT(".$this->BO->getPropObject($propName)->getSize().') NOT NULL,'; |
|
|
|
|
|
|
1388
|
|
|
} else { |
|
1389
|
|
|
$sqlQuery .= "$propName INT(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1390
|
|
|
} |
|
1391
|
|
|
break; |
|
1392
|
|
|
case 'DOUBLE': |
|
1393
|
|
|
$sqlQuery .= "$propName REAL(".$this->BO->getPropObject($propName)->getSize(true).'),'; |
|
|
|
|
|
|
1394
|
|
|
break; |
|
1395
|
|
|
case 'SMALLTEXT': |
|
1396
|
|
|
$sqlQuery .= "$propName TEXT(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1397
|
|
|
break; |
|
1398
|
|
|
case 'TEXT': |
|
1399
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1400
|
|
|
break; |
|
1401
|
|
|
case 'BOOLEAN': |
|
1402
|
|
|
$sqlQuery .= "$propName INTEGER(1) DEFAULT '0',"; |
|
1403
|
|
|
break; |
|
1404
|
|
|
case 'DATE': |
|
1405
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1406
|
|
|
break; |
|
1407
|
|
|
case 'TIMESTAMP': |
|
1408
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1409
|
|
|
break; |
|
1410
|
|
|
case 'ENUM': |
|
1411
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1412
|
|
|
break; |
|
1413
|
|
|
case 'DENUM': |
|
1414
|
|
|
$tmp = new DEnum(get_class($this->BO).'::'.$propName); |
|
|
|
|
|
|
1415
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1416
|
|
|
break; |
|
1417
|
|
|
case 'RELATION': |
|
1418
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1419
|
|
|
break; |
|
1420
|
|
|
default: |
|
1421
|
|
|
$sqlQuery .= ''; |
|
1422
|
|
|
break; |
|
1423
|
|
|
} |
|
1424
|
|
|
} |
|
1425
|
|
|
} |
|
1426
|
|
|
|
|
1427
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1428
|
|
|
$sqlQuery .= 'classname TEXT(100),'; |
|
1429
|
|
|
} |
|
1430
|
|
|
|
|
1431
|
|
|
$sqlQuery .= 'PRIMARY KEY (OID, version_num));'; |
|
1432
|
|
|
|
|
1433
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1434
|
|
|
|
|
1435
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1436
|
|
|
self::$logger->debug('<<makeHistoryTable'); |
|
1437
|
|
|
throw new AlphaException('Failed to create the table ['.$this->BO->getTableName().'_history] for the class ['.get_class($this->BO).'], database error is ['.self::getLastDatabaseError().']'); |
|
1438
|
|
|
} |
|
1439
|
|
|
|
|
1440
|
|
|
self::$logger->debug('<<makeHistoryTable'); |
|
1441
|
|
|
} |
|
1442
|
|
|
|
|
1443
|
|
|
/** |
|
1444
|
|
|
* (non-PHPdoc). |
|
1445
|
|
|
* |
|
1446
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::rebuildTable() |
|
1447
|
|
|
*/ |
|
1448
|
|
View Code Duplication |
public function rebuildTable() |
|
|
|
|
|
|
1449
|
|
|
{ |
|
1450
|
|
|
self::$logger->debug('>>rebuildTable()'); |
|
1451
|
|
|
|
|
1452
|
|
|
// the use of "IF EXISTS" here requires SQLite 3.3.0 or above. |
|
1453
|
|
|
$sqlQuery = 'DROP TABLE IF EXISTS '.$this->BO->getTableName().';'; |
|
1454
|
|
|
|
|
1455
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1456
|
|
|
|
|
1457
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1458
|
|
|
self::$logger->debug('<<rebuildTable'); |
|
1459
|
|
|
throw new AlphaException('Failed to drop the table ['.$this->BO->getTableName().'] for the class ['.get_class($this->BO).'], database error is ['.self::getLastDatabaseError().']'); |
|
1460
|
|
|
} |
|
1461
|
|
|
|
|
1462
|
|
|
$this->BO->makeTable(); |
|
1463
|
|
|
|
|
1464
|
|
|
self::$logger->debug('<<rebuildTable'); |
|
1465
|
|
|
} |
|
1466
|
|
|
|
|
1467
|
|
|
/** |
|
1468
|
|
|
* (non-PHPdoc). |
|
1469
|
|
|
* |
|
1470
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::dropTable() |
|
1471
|
|
|
*/ |
|
1472
|
|
View Code Duplication |
public function dropTable($tableName = null) |
|
|
|
|
|
|
1473
|
|
|
{ |
|
1474
|
|
|
self::$logger->debug('>>dropTable()'); |
|
1475
|
|
|
|
|
1476
|
|
|
if ($tableName == null) { |
|
|
|
|
|
|
1477
|
|
|
$tableName = $this->BO->getTableName(); |
|
1478
|
|
|
} |
|
1479
|
|
|
|
|
1480
|
|
|
// the use of "IF EXISTS" here requires SQLite 3.3.0 or above. |
|
1481
|
|
|
$sqlQuery = 'DROP TABLE IF EXISTS '.$tableName.';'; |
|
1482
|
|
|
|
|
1483
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1484
|
|
|
|
|
1485
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1486
|
|
|
self::$logger->debug('<<dropTable'); |
|
1487
|
|
|
throw new AlphaException('Failed to drop the table ['.$tableName.'] for the class ['.get_class($this->BO).'], query is ['.$this->BO->getLastQuery().']'); |
|
1488
|
|
|
} |
|
1489
|
|
|
|
|
1490
|
|
|
if ($this->BO->getMaintainHistory()) { |
|
1491
|
|
|
$sqlQuery = 'DROP TABLE IF EXISTS '.$tableName.'_history;'; |
|
1492
|
|
|
|
|
1493
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1494
|
|
|
|
|
1495
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1496
|
|
|
self::$logger->debug('<<dropTable'); |
|
1497
|
|
|
throw new AlphaException('Failed to drop the table ['.$tableName.'_history] for the class ['.get_class($this->BO).'], query is ['.$this->BO->getLastQuery().']'); |
|
1498
|
|
|
} |
|
1499
|
|
|
} |
|
1500
|
|
|
|
|
1501
|
|
|
self::$logger->debug('<<dropTable'); |
|
1502
|
|
|
} |
|
1503
|
|
|
|
|
1504
|
|
|
/** |
|
1505
|
|
|
* (non-PHPdoc). |
|
1506
|
|
|
* |
|
1507
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::addProperty() |
|
1508
|
|
|
*/ |
|
1509
|
|
|
public function addProperty($propName) |
|
1510
|
|
|
{ |
|
1511
|
|
|
self::$logger->debug('>>addProperty(propName=['.$propName.'])'); |
|
1512
|
|
|
|
|
1513
|
|
|
$sqlQuery = 'ALTER TABLE '.$this->BO->getTableName().' ADD '; |
|
1514
|
|
|
|
|
1515
|
|
|
if ($this->isTableOverloaded() && $propName == 'classname') { |
|
1516
|
|
|
$sqlQuery .= 'classname TEXT(100)'; |
|
1517
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
1518
|
|
|
if (!in_array($propName, $this->BO->getDefaultAttributes()) && !in_array($propName, $this->BO->getTransientAttributes())) { |
|
1519
|
|
|
$reflection = new ReflectionClass($this->BO->getPropObject($propName)); |
|
1520
|
|
|
$propClass = $reflection->getShortName(); |
|
1521
|
|
|
|
|
1522
|
|
|
switch (mb_strtoupper($propClass)) { |
|
1523
|
|
|
case 'INTEGER': |
|
1524
|
|
|
// special properties for RelationLookup OIDs |
|
1525
|
|
|
if ($this->BO instanceof RelationLookup && ($propName == 'leftID' || $propName == 'rightID')) { |
|
1526
|
|
|
$sqlQuery .= "$propName INTEGER(".$this->BO->getPropObject($propName)->getSize().') NOT NULL,'; |
|
|
|
|
|
|
1527
|
|
|
} else { |
|
1528
|
|
|
$sqlQuery .= "$propName INTEGER(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1529
|
|
|
} |
|
1530
|
|
|
break; |
|
1531
|
|
|
case 'DOUBLE': |
|
1532
|
|
|
$sqlQuery .= "$propName REAL(".$this->BO->getPropObject($propName)->getSize(true).'),'; |
|
|
|
|
|
|
1533
|
|
|
break; |
|
1534
|
|
|
case 'SMALLTEXT': |
|
1535
|
|
|
$sqlQuery .= "$propName TEXT(".$this->BO->getPropObject($propName)->getSize().'),'; |
|
|
|
|
|
|
1536
|
|
|
break; |
|
1537
|
|
|
case 'TEXT': |
|
1538
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1539
|
|
|
break; |
|
1540
|
|
|
case 'BOOLEAN': |
|
1541
|
|
|
$sqlQuery .= "$propName INTEGER(1) DEFAULT '0',"; |
|
1542
|
|
|
break; |
|
1543
|
|
|
case 'DATE': |
|
1544
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1545
|
|
|
break; |
|
1546
|
|
|
case 'TIMESTAMP': |
|
1547
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1548
|
|
|
break; |
|
1549
|
|
|
case 'ENUM': |
|
1550
|
|
|
$sqlQuery .= "$propName TEXT,"; |
|
1551
|
|
|
break; |
|
1552
|
|
|
case 'DENUM': |
|
1553
|
|
|
$tmp = new DEnum(get_class($this->BO).'::'.$propName); |
|
|
|
|
|
|
1554
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1555
|
|
|
break; |
|
1556
|
|
|
case 'RELATION': |
|
1557
|
|
|
$sqlQuery .= "$propName INTEGER(11),"; |
|
1558
|
|
|
break; |
|
1559
|
|
|
default: |
|
1560
|
|
|
$sqlQuery .= ''; |
|
1561
|
|
|
break; |
|
1562
|
|
|
} |
|
1563
|
|
|
} |
|
1564
|
|
|
} |
|
1565
|
|
|
|
|
1566
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1567
|
|
|
|
|
1568
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1569
|
|
|
self::$logger->debug('<<addProperty'); |
|
1570
|
|
|
throw new AlphaException('Failed to add the new attribute ['.$propName.'] to the table ['.$this->BO->getTableName().'], query is ['.$this->BO->getLastQuery().']'); |
|
1571
|
|
|
} else { |
|
1572
|
|
|
self::$logger->info('Successfully added the ['.$propName.'] column onto the ['.$this->BO->getTableName().'] table for the class ['.get_class($this->BO).']'); |
|
1573
|
|
|
} |
|
1574
|
|
|
|
|
1575
|
|
View Code Duplication |
if ($this->BO->getMaintainHistory()) { |
|
|
|
|
|
|
1576
|
|
|
$sqlQuery = str_replace($this->BO->getTableName(), $this->BO->getTableName().'_history', $sqlQuery); |
|
1577
|
|
|
|
|
1578
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1579
|
|
|
self::$logger->debug('<<addProperty'); |
|
1580
|
|
|
throw new AlphaException('Failed to add the new attribute ['.$propName.'] to the table ['.$this->BO->getTableName().'_history], query is ['.$this->BO->getLastQuery().']'); |
|
1581
|
|
|
} else { |
|
1582
|
|
|
self::$logger->info('Successfully added the ['.$propName.'] column onto the ['.$this->BO->getTableName().'_history] table for the class ['.get_class($this->BO).']'); |
|
1583
|
|
|
} |
|
1584
|
|
|
} |
|
1585
|
|
|
|
|
1586
|
|
|
self::$logger->debug('<<addProperty'); |
|
1587
|
|
|
} |
|
1588
|
|
|
|
|
1589
|
|
|
/** |
|
1590
|
|
|
* (non-PHPdoc). |
|
1591
|
|
|
* |
|
1592
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getMAX() |
|
1593
|
|
|
*/ |
|
1594
|
|
View Code Duplication |
public function getMAX() |
|
|
|
|
|
|
1595
|
|
|
{ |
|
1596
|
|
|
self::$logger->debug('>>getMAX()'); |
|
1597
|
|
|
|
|
1598
|
|
|
$sqlQuery = 'SELECT MAX(OID) AS max_OID FROM '.$this->BO->getTableName(); |
|
1599
|
|
|
|
|
1600
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1601
|
|
|
|
|
1602
|
|
|
try { |
|
1603
|
|
|
$result = $this->BO->query($sqlQuery); |
|
1604
|
|
|
|
|
1605
|
|
|
$row = $result[0]; |
|
1606
|
|
|
|
|
1607
|
|
|
if (isset($row['max_OID'])) { |
|
1608
|
|
|
self::$logger->debug('<<getMAX ['.$row['max_OID'].']'); |
|
1609
|
|
|
|
|
1610
|
|
|
return $row['max_OID']; |
|
1611
|
|
|
} else { |
|
1612
|
|
|
throw new AlphaException('Failed to get the MAX ID for the class ['.get_class($this->BO).'] from the table ['.$this->BO->getTableName().'], query is ['.$this->BO->getLastQuery().']'); |
|
1613
|
|
|
} |
|
1614
|
|
|
} catch (Exception $e) { |
|
1615
|
|
|
self::$logger->debug('<<getMAX'); |
|
1616
|
|
|
throw new AlphaException($e->getMessage()); |
|
1617
|
|
|
} |
|
1618
|
|
|
} |
|
1619
|
|
|
|
|
1620
|
|
|
/** |
|
1621
|
|
|
* (non-PHPdoc). |
|
1622
|
|
|
* |
|
1623
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getCount() |
|
1624
|
|
|
*/ |
|
1625
|
|
|
public function getCount($attributes = array(), $values = array()) |
|
1626
|
|
|
{ |
|
1627
|
|
|
self::$logger->debug('>>getCount(attributes=['.var_export($attributes, true).'], values=['.var_export($values, true).'])'); |
|
1628
|
|
|
|
|
1629
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1630
|
|
|
$whereClause = ' WHERE classname = \''.addslashes(get_class($this->BO)).'\' AND'; |
|
1631
|
|
|
} else { |
|
1632
|
|
|
$whereClause = ' WHERE'; |
|
1633
|
|
|
} |
|
1634
|
|
|
|
|
1635
|
|
|
$count = count($attributes); |
|
1636
|
|
|
|
|
1637
|
|
|
for ($i = 0; $i < $count; ++$i) { |
|
1638
|
|
|
$whereClause .= ' '.$attributes[$i].' = \''.$values[$i].'\' AND'; |
|
1639
|
|
|
self::$logger->debug($whereClause); |
|
1640
|
|
|
} |
|
1641
|
|
|
// remove the last " AND" |
|
1642
|
|
|
$whereClause = mb_substr($whereClause, 0, -4); |
|
1643
|
|
|
|
|
1644
|
|
|
if ($whereClause != ' WHERE') { |
|
1645
|
|
|
$sqlQuery = 'SELECT COUNT(OID) AS class_count FROM '.$this->BO->getTableName().$whereClause; |
|
1646
|
|
|
} else { |
|
1647
|
|
|
$sqlQuery = 'SELECT COUNT(OID) AS class_count FROM '.$this->BO->getTableName(); |
|
1648
|
|
|
} |
|
1649
|
|
|
|
|
1650
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1651
|
|
|
|
|
1652
|
|
View Code Duplication |
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
|
|
|
|
|
1653
|
|
|
self::$logger->debug('<<getCount'); |
|
1654
|
|
|
throw new AlphaException('Failed to get the count for the class ['.get_class($this->BO).'] from the table ['.$this->BO->getTableName().'], query is ['.$this->BO->getLastQuery().']'); |
|
1655
|
|
|
} else { |
|
1656
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
1657
|
|
|
|
|
1658
|
|
|
self::$logger->debug('<<getCount ['.$row['class_count'].']'); |
|
1659
|
|
|
|
|
1660
|
|
|
return $row['class_count']; |
|
1661
|
|
|
} |
|
1662
|
|
|
} |
|
1663
|
|
|
|
|
1664
|
|
|
/** |
|
1665
|
|
|
* (non-PHPdoc). |
|
1666
|
|
|
* |
|
1667
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getHistoryCount() |
|
1668
|
|
|
*/ |
|
1669
|
|
|
public function getHistoryCount() |
|
1670
|
|
|
{ |
|
1671
|
|
|
self::$logger->debug('>>getHistoryCount()'); |
|
1672
|
|
|
|
|
1673
|
|
|
if (!$this->BO->getMaintainHistory()) { |
|
1674
|
|
|
throw new AlphaException('getHistoryCount method called on a DAO where no history is maintained!'); |
|
1675
|
|
|
} |
|
1676
|
|
|
|
|
1677
|
|
|
$sqlQuery = 'SELECT COUNT(OID) AS object_count FROM '.$this->BO->getTableName().'_history WHERE OID='.$this->BO->getOID(); |
|
1678
|
|
|
|
|
1679
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1680
|
|
|
self::$logger->debug('query ['.$sqlQuery.']'); |
|
1681
|
|
|
|
|
1682
|
|
View Code Duplication |
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
|
|
|
|
|
1683
|
|
|
self::$logger->debug('<<getHistoryCount'); |
|
1684
|
|
|
throw new AlphaException('Failed to get the history count for the business object ['.$this->BO->getOID().'] from the table ['.$this->BO->getTableName().'_history], query is ['.$this->BO->getLastQuery().']'); |
|
1685
|
|
|
} else { |
|
1686
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
1687
|
|
|
|
|
1688
|
|
|
self::$logger->debug('<<getHistoryCount ['.$row['object_count'].']'); |
|
1689
|
|
|
|
|
1690
|
|
|
return $row['object_count']; |
|
1691
|
|
|
} |
|
1692
|
|
|
} |
|
1693
|
|
|
|
|
1694
|
|
|
/** |
|
1695
|
|
|
* Given that Enum values are not saved in the database for SQLite, an implementation is not required here. |
|
1696
|
|
|
* |
|
1697
|
|
|
* (non-PHPdoc) |
|
1698
|
|
|
* |
|
1699
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::setEnumOptions() |
|
1700
|
|
|
* |
|
1701
|
|
|
* @throws \Alpha\Exception\NotImplementedException |
|
1702
|
|
|
*/ |
|
1703
|
|
|
public function setEnumOptions() |
|
1704
|
|
|
{ |
|
1705
|
|
|
throw new NotImplementedException('ActiveRecordProviderInterface::setEnumOptions() not implemented by the SQLite3 provider'); |
|
1706
|
|
|
} |
|
1707
|
|
|
|
|
1708
|
|
|
/** |
|
1709
|
|
|
* (non-PHPdoc). |
|
1710
|
|
|
* |
|
1711
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::checkTableExists() |
|
1712
|
|
|
*/ |
|
1713
|
|
View Code Duplication |
public function checkTableExists($checkHistoryTable = false) |
|
|
|
|
|
|
1714
|
|
|
{ |
|
1715
|
|
|
self::$logger->debug('>>checkTableExists(checkHistoryTable=['.$checkHistoryTable.'])'); |
|
1716
|
|
|
|
|
1717
|
|
|
$config = ConfigProvider::getInstance(); |
|
|
|
|
|
|
1718
|
|
|
|
|
1719
|
|
|
$tableExists = false; |
|
1720
|
|
|
|
|
1721
|
|
|
$sqlQuery = 'SELECT name FROM sqlite_master WHERE type = "table";'; |
|
1722
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1723
|
|
|
|
|
1724
|
|
|
$result = self::getConnection()->query($sqlQuery); |
|
1725
|
|
|
|
|
1726
|
|
|
$tableName = ($checkHistoryTable ? $this->BO->getTableName().'_history' : $this->BO->getTableName()); |
|
1727
|
|
|
|
|
1728
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1729
|
|
|
if (strtolower($row['name']) == mb_strtolower($tableName)) { |
|
1730
|
|
|
$tableExists = true; |
|
1731
|
|
|
} |
|
1732
|
|
|
} |
|
1733
|
|
|
|
|
1734
|
|
|
if ($result) { |
|
1735
|
|
|
self::$logger->debug('<<checkTableExists ['.$tableExists.']'); |
|
1736
|
|
|
|
|
1737
|
|
|
return $tableExists; |
|
1738
|
|
|
} else { |
|
1739
|
|
|
self::$logger->debug('<<checkTableExists'); |
|
1740
|
|
|
throw new AlphaException('Failed to access the system database correctly, error is ['.self::getLastDatabaseError().']'); |
|
1741
|
|
|
} |
|
1742
|
|
|
} |
|
1743
|
|
|
|
|
1744
|
|
|
/** |
|
1745
|
|
|
* (non-PHPdoc). |
|
1746
|
|
|
* |
|
1747
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::checkBOTableExists() |
|
1748
|
|
|
*/ |
|
1749
|
|
View Code Duplication |
public static function checkBOTableExists($BOClassName, $checkHistoryTable = false) |
|
|
|
|
|
|
1750
|
|
|
{ |
|
1751
|
|
|
if (self::$logger == null) { |
|
1752
|
|
|
self::$logger = new Logger('ActiveRecordProviderSQLite'); |
|
1753
|
|
|
} |
|
1754
|
|
|
self::$logger->debug('>>checkBOTableExists(BOClassName=['.$BOClassName.'], checkHistoryTable=['.$checkHistoryTable.'])'); |
|
1755
|
|
|
|
|
1756
|
|
|
if (!class_exists($BOClassName)) { |
|
1757
|
|
|
throw new IllegalArguementException('The classname provided ['.$checkHistoryTable.'] is not defined!'); |
|
1758
|
|
|
} |
|
1759
|
|
|
|
|
1760
|
|
|
$tableName = $BOClassName::TABLE_NAME; |
|
1761
|
|
|
|
|
1762
|
|
|
if (empty($tableName)) { |
|
1763
|
|
|
$tableName = mb_substr($BOClassName, 0, mb_strpos($BOClassName, '_')); |
|
1764
|
|
|
} |
|
1765
|
|
|
|
|
1766
|
|
|
if ($checkHistoryTable) { |
|
1767
|
|
|
$tableName .= '_history'; |
|
1768
|
|
|
} |
|
1769
|
|
|
|
|
1770
|
|
|
$tableExists = false; |
|
1771
|
|
|
|
|
1772
|
|
|
$sqlQuery = 'SELECT name FROM sqlite_master WHERE type = "table";'; |
|
1773
|
|
|
|
|
1774
|
|
|
$result = self::getConnection()->query($sqlQuery); |
|
1775
|
|
|
|
|
1776
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1777
|
|
|
if ($row['name'] == $tableName) { |
|
1778
|
|
|
$tableExists = true; |
|
1779
|
|
|
} |
|
1780
|
|
|
} |
|
1781
|
|
|
|
|
1782
|
|
|
if ($result) { |
|
1783
|
|
|
self::$logger->debug('<<checkBOTableExists ['.($tableExists ? 'true' : 'false').']'); |
|
1784
|
|
|
|
|
1785
|
|
|
return $tableExists; |
|
1786
|
|
|
} else { |
|
1787
|
|
|
self::$logger->debug('<<checkBOTableExists'); |
|
1788
|
|
|
throw new AlphaException('Failed to access the system database correctly, error is ['.self::getLastDatabaseError().']'); |
|
1789
|
|
|
} |
|
1790
|
|
|
} |
|
1791
|
|
|
|
|
1792
|
|
|
/** |
|
1793
|
|
|
* (non-PHPdoc). |
|
1794
|
|
|
* |
|
1795
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::checkTableNeedsUpdate() |
|
1796
|
|
|
*/ |
|
1797
|
|
View Code Duplication |
public function checkTableNeedsUpdate() |
|
|
|
|
|
|
1798
|
|
|
{ |
|
1799
|
|
|
self::$logger->debug('>>checkTableNeedsUpdate()'); |
|
1800
|
|
|
|
|
1801
|
|
|
if (!$this->BO->checkTableExists()) { |
|
1802
|
|
|
return false; |
|
1803
|
|
|
} |
|
1804
|
|
|
|
|
1805
|
|
|
$updateRequired = false; |
|
1806
|
|
|
|
|
1807
|
|
|
$matchCount = 0; |
|
1808
|
|
|
|
|
1809
|
|
|
$query = 'PRAGMA table_info('.$this->BO->getTableName().')'; |
|
1810
|
|
|
$result = self::getConnection()->query($query); |
|
1811
|
|
|
$this->BO->setLastQuery($query); |
|
1812
|
|
|
|
|
1813
|
|
|
// get the class attributes |
|
1814
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
1815
|
|
|
$properties = $reflection->getProperties(); |
|
1816
|
|
|
|
|
1817
|
|
|
foreach ($properties as $propObj) { |
|
1818
|
|
|
$propName = $propObj->name; |
|
1819
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
1820
|
|
|
$foundMatch = false; |
|
1821
|
|
|
|
|
1822
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1823
|
|
|
if ($propName == $row['name']) { |
|
1824
|
|
|
$foundMatch = true; |
|
1825
|
|
|
break; |
|
1826
|
|
|
} |
|
1827
|
|
|
} |
|
1828
|
|
|
|
|
1829
|
|
|
if (!$foundMatch) { |
|
1830
|
|
|
--$matchCount; |
|
1831
|
|
|
} |
|
1832
|
|
|
|
|
1833
|
|
|
$result->reset(); |
|
1834
|
|
|
} |
|
1835
|
|
|
} |
|
1836
|
|
|
|
|
1837
|
|
|
// check for the "classname" field in overloaded tables |
|
1838
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1839
|
|
|
$foundMatch = false; |
|
1840
|
|
|
|
|
1841
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1842
|
|
|
if ('classname' == $row['name']) { |
|
1843
|
|
|
$foundMatch = true; |
|
1844
|
|
|
break; |
|
1845
|
|
|
} |
|
1846
|
|
|
} |
|
1847
|
|
|
if (!$foundMatch) { |
|
1848
|
|
|
--$matchCount; |
|
1849
|
|
|
} |
|
1850
|
|
|
} |
|
1851
|
|
|
|
|
1852
|
|
|
if ($matchCount != 0) { |
|
1853
|
|
|
$updateRequired = true; |
|
1854
|
|
|
} |
|
1855
|
|
|
|
|
1856
|
|
|
if (!$result) { |
|
1857
|
|
|
self::$logger->debug('<<checkTableNeedsUpdate'); |
|
1858
|
|
|
throw new AlphaException('Failed to access the system database correctly, error is ['.self::getLastDatabaseError().']'); |
|
1859
|
|
|
} else { |
|
1860
|
|
|
// check the table indexes |
|
1861
|
|
|
try { |
|
1862
|
|
|
$this->checkIndexes(); |
|
1863
|
|
|
} catch (AlphaException $ae) { |
|
1864
|
|
|
self::$logger->warn("Error while checking database indexes:\n\n".$ae->getMessage()); |
|
1865
|
|
|
} |
|
1866
|
|
|
|
|
1867
|
|
|
self::$logger->debug('<<checkTableNeedsUpdate ['.$updateRequired.']'); |
|
1868
|
|
|
|
|
1869
|
|
|
return $updateRequired; |
|
1870
|
|
|
} |
|
1871
|
|
|
} |
|
1872
|
|
|
|
|
1873
|
|
|
/** |
|
1874
|
|
|
* (non-PHPdoc). |
|
1875
|
|
|
* |
|
1876
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::findMissingFields() |
|
1877
|
|
|
*/ |
|
1878
|
|
View Code Duplication |
public function findMissingFields() |
|
|
|
|
|
|
1879
|
|
|
{ |
|
1880
|
|
|
self::$logger->debug('>>findMissingFields()'); |
|
1881
|
|
|
|
|
1882
|
|
|
$missingFields = array(); |
|
1883
|
|
|
$matchCount = 0; |
|
1884
|
|
|
|
|
1885
|
|
|
$sqlQuery = 'PRAGMA table_info('.$this->BO->getTableName().')'; |
|
1886
|
|
|
$result = self::getConnection()->query($sqlQuery); |
|
1887
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1888
|
|
|
|
|
1889
|
|
|
// get the class attributes |
|
1890
|
|
|
$reflection = new ReflectionClass(get_class($this->BO)); |
|
1891
|
|
|
$properties = $reflection->getProperties(); |
|
1892
|
|
|
|
|
1893
|
|
|
foreach ($properties as $propObj) { |
|
1894
|
|
|
$propName = $propObj->name; |
|
1895
|
|
|
if (!in_array($propName, $this->BO->getTransientAttributes())) { |
|
1896
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1897
|
|
|
if ($propName == $row['name']) { |
|
1898
|
|
|
++$matchCount; |
|
1899
|
|
|
break; |
|
1900
|
|
|
} |
|
1901
|
|
|
} |
|
1902
|
|
|
$result->reset(); |
|
1903
|
|
|
} else { |
|
1904
|
|
|
++$matchCount; |
|
1905
|
|
|
} |
|
1906
|
|
|
|
|
1907
|
|
|
if ($matchCount == 0) { |
|
1908
|
|
|
array_push($missingFields, $propName); |
|
1909
|
|
|
} else { |
|
1910
|
|
|
$matchCount = 0; |
|
1911
|
|
|
} |
|
1912
|
|
|
} |
|
1913
|
|
|
|
|
1914
|
|
|
// check for the "classname" field in overloaded tables |
|
1915
|
|
|
if ($this->BO->isTableOverloaded()) { |
|
1916
|
|
|
$foundMatch = false; |
|
1917
|
|
|
|
|
1918
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1919
|
|
|
if ('classname' == $row['name']) { |
|
1920
|
|
|
$foundMatch = true; |
|
1921
|
|
|
break; |
|
1922
|
|
|
} |
|
1923
|
|
|
} |
|
1924
|
|
|
if (!$foundMatch) { |
|
1925
|
|
|
array_push($missingFields, 'classname'); |
|
1926
|
|
|
} |
|
1927
|
|
|
} |
|
1928
|
|
|
|
|
1929
|
|
|
if (!$result) { |
|
1930
|
|
|
throw new AlphaException('Failed to access the system database correctly, error is ['.self::getLastDatabaseError().']'); |
|
1931
|
|
|
} |
|
1932
|
|
|
|
|
1933
|
|
|
self::$logger->debug('<<findMissingFields ['.var_export($missingFields, true).']'); |
|
1934
|
|
|
|
|
1935
|
|
|
return $missingFields; |
|
1936
|
|
|
} |
|
1937
|
|
|
|
|
1938
|
|
|
/** |
|
1939
|
|
|
* (non-PHPdoc). |
|
1940
|
|
|
* |
|
1941
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::getIndexes() |
|
1942
|
|
|
*/ |
|
1943
|
|
|
public function getIndexes() |
|
1944
|
|
|
{ |
|
1945
|
|
|
self::$logger->debug('>>getIndexes()'); |
|
1946
|
|
|
|
|
1947
|
|
|
$sqlQuery = "SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='".$this->BO->getTableName()."'"; |
|
1948
|
|
|
|
|
1949
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1950
|
|
|
|
|
1951
|
|
|
$indexNames = array(); |
|
1952
|
|
|
|
|
1953
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1954
|
|
|
throw new AlphaException('Failed to access the system database correctly, error is ['.self::getLastDatabaseError().']'); |
|
1955
|
|
|
} else { |
|
1956
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1957
|
|
|
array_push($indexNames, $row['name']); |
|
1958
|
|
|
} |
|
1959
|
|
|
} |
|
1960
|
|
|
|
|
1961
|
|
|
// in SQLite foreign keys are not stored in sqlite_master, so we have to run a different query and append the results |
|
1962
|
|
|
$sqlQuery = 'PRAGMA foreign_key_list('.$this->BO->getTableName().')'; |
|
1963
|
|
|
|
|
1964
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
1965
|
|
|
|
|
1966
|
|
|
if (!$result = self::getConnection()->query($sqlQuery)) { |
|
1967
|
|
|
self::$logger->warn('Error during pragma table foreign key lookup ['.self::getLastDatabaseError().']'); |
|
1968
|
|
|
} else { |
|
1969
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
1970
|
|
|
// SQLite does not name FK indexes, so we will return a fake name based the same convention used in MySQL |
|
1971
|
|
|
$fakeIndexName = $this->BO->getTableName().'_'.$row['from'].'_fk_idx'; |
|
1972
|
|
|
array_push($indexNames, $fakeIndexName); |
|
1973
|
|
|
} |
|
1974
|
|
|
} |
|
1975
|
|
|
|
|
1976
|
|
|
self::$logger->debug('<<getIndexes'); |
|
1977
|
|
|
|
|
1978
|
|
|
return $indexNames; |
|
1979
|
|
|
} |
|
1980
|
|
|
|
|
1981
|
|
|
/** |
|
1982
|
|
|
* Checks to see if all of the indexes are in place for the BO's table, creates those that are missing. |
|
1983
|
|
|
* |
|
1984
|
|
|
* @since 1.2 |
|
1985
|
|
|
*/ |
|
1986
|
|
|
private function checkIndexes() |
|
1987
|
|
|
{ |
|
1988
|
|
|
self::$logger->debug('>>checkIndexes()'); |
|
1989
|
|
|
|
|
1990
|
|
|
$indexNames = $this->BO->getIndexes(); |
|
1991
|
|
|
|
|
1992
|
|
|
// process unique keys |
|
1993
|
|
View Code Duplication |
foreach ($this->BO->getUniqueAttributes() as $prop) { |
|
|
|
|
|
|
1994
|
|
|
// check for composite indexes |
|
1995
|
|
|
if (mb_strpos($prop, '+')) { |
|
1996
|
|
|
$attributes = explode('+', $prop); |
|
1997
|
|
|
|
|
1998
|
|
|
$index_exists = false; |
|
1999
|
|
|
foreach ($indexNames as $index) { |
|
2000
|
|
|
if ($attributes[0].'_'.$attributes[1].'_unq_idx' == $index) { |
|
2001
|
|
|
$index_exists = true; |
|
2002
|
|
|
} |
|
2003
|
|
|
if (count($attributes) == 3) { |
|
2004
|
|
|
if ($attributes[0].'_'.$attributes[1].'_'.$attributes[2].'_unq_idx' == $index) { |
|
2005
|
|
|
$index_exists = true; |
|
2006
|
|
|
} |
|
2007
|
|
|
} |
|
2008
|
|
|
} |
|
2009
|
|
|
|
|
2010
|
|
|
if (!$index_exists) { |
|
2011
|
|
|
if (count($attributes) == 3) { |
|
2012
|
|
|
$this->BO->createUniqueIndex($attributes[0], $attributes[1], $attributes[2]); |
|
2013
|
|
|
} else { |
|
2014
|
|
|
$this->BO->createUniqueIndex($attributes[0], $attributes[1]); |
|
2015
|
|
|
} |
|
2016
|
|
|
} |
|
2017
|
|
|
} else { |
|
2018
|
|
|
$index_exists = false; |
|
2019
|
|
|
foreach ($indexNames as $index) { |
|
2020
|
|
|
if ($prop.'_unq_idx' == $index) { |
|
2021
|
|
|
$index_exists = true; |
|
2022
|
|
|
} |
|
2023
|
|
|
} |
|
2024
|
|
|
|
|
2025
|
|
|
if (!$index_exists) { |
|
2026
|
|
|
$this->createUniqueIndex($prop); |
|
2027
|
|
|
} |
|
2028
|
|
|
} |
|
2029
|
|
|
} |
|
2030
|
|
|
|
|
2031
|
|
|
self::$logger->debug('<<checkIndexes'); |
|
2032
|
|
|
} |
|
2033
|
|
|
|
|
2034
|
|
|
/** |
|
2035
|
|
|
* Note that SQLite 3.6.19 is requrired for foreign key support. |
|
2036
|
|
|
* |
|
2037
|
|
|
* (non-PHPdoc) |
|
2038
|
|
|
* |
|
2039
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::createForeignIndex() |
|
2040
|
|
|
*/ |
|
2041
|
|
|
public function createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute, $indexName = null) |
|
2042
|
|
|
{ |
|
2043
|
|
|
self::$logger->info('>>createForeignIndex(attributeName=['.$attributeName.'], relatedClass=['.$relatedClass.'], relatedClassAttribute=['.$relatedClassAttribute.'], indexName=['.$indexName.']'); |
|
2044
|
|
|
|
|
2045
|
|
|
/* |
|
2046
|
|
|
* High-level approach |
|
2047
|
|
|
* |
|
2048
|
|
|
* 1. Rename the source table to [tablename]_temp |
|
2049
|
|
|
* 2. Create a new [tablename] table, with the new FK in place. |
|
2050
|
|
|
* 3. Copy all of the data from [tablename]_temp to [tablename]. |
|
2051
|
|
|
* 4. Drop [tablename]_temp. |
|
2052
|
|
|
*/ |
|
2053
|
|
|
try { |
|
2054
|
|
|
ActiveRecord::begin($this->BO); |
|
2055
|
|
|
|
|
2056
|
|
|
// rename the table to [tablename]_temp |
|
2057
|
|
|
$query = 'ALTER TABLE '.$this->BO->getTableName().' RENAME TO '.$this->BO->getTableName().'_temp;'; |
|
2058
|
|
|
$this->BO->setLastQuery($query); |
|
2059
|
|
|
self::getConnection()->query($query); |
|
2060
|
|
|
|
|
2061
|
|
|
self::$logger->info('Renamed the table ['.$this->BO->getTableName().'] to ['.$this->BO->getTableName().'_temp]'); |
|
2062
|
|
|
|
|
2063
|
|
|
// now create the new table with the FK in place |
|
2064
|
|
|
$record = new $relatedClass(); |
|
2065
|
|
|
$tableName = $record->getTableName(); |
|
2066
|
|
|
$this->foreignKeys[$attributeName] = array($tableName, $relatedClassAttribute); |
|
2067
|
|
|
|
|
2068
|
|
|
$this->makeTable(); |
|
2069
|
|
|
|
|
2070
|
|
|
self::$logger->info('Made a new copy of the table ['.$this->BO->getTableName().']'); |
|
2071
|
|
|
|
|
2072
|
|
|
// copy all of the old data to the new table |
|
2073
|
|
|
$query = 'INSERT INTO '.$this->BO->getTableName().' SELECT * FROM '.$this->BO->getTableName().'_temp;'; |
|
2074
|
|
|
$this->BO->setLastQuery($query); |
|
2075
|
|
|
self::getConnection()->query($query); |
|
2076
|
|
|
|
|
2077
|
|
|
self::$logger->info('Copied all of the data from ['.$this->BO->getTableName().'] to ['.$this->BO->getTableName().'_temp]'); |
|
2078
|
|
|
|
|
2079
|
|
|
// finally, drop the _temp table and commit the changes |
|
2080
|
|
|
$this->BO->dropTable($this->BO->getTableName().'_temp'); |
|
2081
|
|
|
|
|
2082
|
|
|
self::$logger->info('Dropped the table ['.$this->BO->getTableName().'_temp]'); |
|
2083
|
|
|
|
|
2084
|
|
|
ActiveRecord::commit($this->BO); |
|
2085
|
|
|
} catch (Exception $e) { |
|
2086
|
|
|
ActiveRecord::rollback($this->BO); |
|
2087
|
|
|
|
|
2088
|
|
|
throw new FailedIndexCreateException('Failed to create the index ['.$attributeName.'] on ['.$this->BO->getTableName().'], error is ['.$e->getMessage().'], query ['.$this->BO->getLastQuery().']'); |
|
2089
|
|
|
} |
|
2090
|
|
|
|
|
2091
|
|
|
self::$logger->info('<<createForeignIndex'); |
|
2092
|
|
|
} |
|
2093
|
|
|
|
|
2094
|
|
|
/** |
|
2095
|
|
|
* (non-PHPdoc). |
|
2096
|
|
|
* |
|
2097
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::createUniqueIndex() |
|
2098
|
|
|
*/ |
|
2099
|
|
View Code Duplication |
public function createUniqueIndex($attribute1Name, $attribute2Name = '', $attribute3Name = '') |
|
|
|
|
|
|
2100
|
|
|
{ |
|
2101
|
|
|
self::$logger->debug('>>createUniqueIndex(attribute1Name=['.$attribute1Name.'], attribute2Name=['.$attribute2Name.'], attribute3Name=['.$attribute3Name.'])'); |
|
2102
|
|
|
|
|
2103
|
|
|
if ($attribute2Name != '' && $attribute3Name != '') { |
|
2104
|
|
|
$sqlQuery = 'CREATE UNIQUE INDEX IF NOT EXISTS '.$attribute1Name.'_'.$attribute2Name.'_'.$attribute3Name.'_unq_idx ON '.$this->BO->getTableName().' ('.$attribute1Name.','.$attribute2Name.','.$attribute3Name.');'; |
|
2105
|
|
|
} |
|
2106
|
|
|
|
|
2107
|
|
|
if ($attribute2Name != '' && $attribute3Name == '') { |
|
2108
|
|
|
$sqlQuery = 'CREATE UNIQUE INDEX IF NOT EXISTS '.$attribute1Name.'_'.$attribute2Name.'_unq_idx ON '.$this->BO->getTableName().' ('.$attribute1Name.','.$attribute2Name.');'; |
|
2109
|
|
|
} |
|
2110
|
|
|
|
|
2111
|
|
|
if ($attribute2Name == '' && $attribute3Name == '') { |
|
2112
|
|
|
$sqlQuery = 'CREATE UNIQUE INDEX IF NOT EXISTS '.$attribute1Name.'_unq_idx ON '.$this->BO->getTableName().' ('.$attribute1Name.');'; |
|
2113
|
|
|
} |
|
2114
|
|
|
|
|
2115
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
|
|
|
|
|
2116
|
|
|
|
|
2117
|
|
|
$result = self::getConnection()->query($sqlQuery); |
|
2118
|
|
|
|
|
2119
|
|
|
if ($result) { |
|
2120
|
|
|
self::$logger->debug('Successfully created the unique index on ['.$this->BO->getTableName().']'); |
|
2121
|
|
|
} else { |
|
2122
|
|
|
throw new FailedIndexCreateException('Failed to create the unique index on ['.$this->BO->getTableName().'], error is ['.self::getConnection()->error.']'); |
|
|
|
|
|
|
2123
|
|
|
} |
|
2124
|
|
|
|
|
2125
|
|
|
self::$logger->debug('<<createUniqueIndex'); |
|
2126
|
|
|
} |
|
2127
|
|
|
|
|
2128
|
|
|
/** |
|
2129
|
|
|
* (non-PHPdoc). |
|
2130
|
|
|
* |
|
2131
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::reload() |
|
2132
|
|
|
*/ |
|
2133
|
|
View Code Duplication |
public function reload() |
|
|
|
|
|
|
2134
|
|
|
{ |
|
2135
|
|
|
self::$logger->debug('>>reload()'); |
|
2136
|
|
|
|
|
2137
|
|
|
if (!$this->BO->isTransient()) { |
|
2138
|
|
|
$this->BO->load($this->BO->getOID()); |
|
2139
|
|
|
} else { |
|
2140
|
|
|
throw new AlphaException('Cannot reload transient object from database!'); |
|
2141
|
|
|
} |
|
2142
|
|
|
|
|
2143
|
|
|
self::$logger->debug('<<reload'); |
|
2144
|
|
|
} |
|
2145
|
|
|
|
|
2146
|
|
|
/** |
|
2147
|
|
|
* (non-PHPdoc). |
|
2148
|
|
|
* |
|
2149
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::checkRecordExists() |
|
2150
|
|
|
*/ |
|
2151
|
|
|
public function checkRecordExists($OID) |
|
2152
|
|
|
{ |
|
2153
|
|
|
self::$logger->debug('>>checkRecordExists(OID=['.$OID.'])'); |
|
2154
|
|
|
|
|
2155
|
|
|
$sqlQuery = 'SELECT OID FROM '.$this->BO->getTableName().' WHERE OID = :OID;'; |
|
2156
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
2157
|
|
|
$stmt = self::getConnection()->prepare($sqlQuery); |
|
2158
|
|
|
|
|
2159
|
|
|
$row = array(); |
|
|
|
|
|
|
2160
|
|
|
|
|
2161
|
|
|
if ($stmt instanceof SQLite3Stmt) { |
|
2162
|
|
|
$stmt->bindValue(':OID', $OID, SQLITE3_INTEGER); |
|
2163
|
|
|
|
|
2164
|
|
|
$result = $stmt->execute(); |
|
2165
|
|
|
|
|
2166
|
|
|
// there should only ever be one (or none) |
|
2167
|
|
|
$row = $result->fetchArray(SQLITE3_ASSOC); |
|
2168
|
|
|
|
|
2169
|
|
|
$stmt->close(); |
|
2170
|
|
|
} else { |
|
2171
|
|
|
self::$logger->debug('<<checkRecordExists'); |
|
2172
|
|
|
throw new AlphaException('Failed to check for the record ['.$OID.'] on the class ['.get_class($this->BO).'] from the table ['.$this->BO->getTableName().'], query is ['.$this->BO->getLastQuery().']'); |
|
2173
|
|
|
} |
|
2174
|
|
|
|
|
2175
|
|
View Code Duplication |
if (!isset($row['OID'])) { |
|
|
|
|
|
|
2176
|
|
|
self::$logger->debug('<<checkRecordExists [false]'); |
|
2177
|
|
|
|
|
2178
|
|
|
return false; |
|
2179
|
|
|
} else { |
|
2180
|
|
|
self::$logger->debug('<<checkRecordExists [true]'); |
|
2181
|
|
|
|
|
2182
|
|
|
return true; |
|
2183
|
|
|
} |
|
2184
|
|
|
} |
|
2185
|
|
|
|
|
2186
|
|
|
/** |
|
2187
|
|
|
* (non-PHPdoc). |
|
2188
|
|
|
* |
|
2189
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::isTableOverloaded() |
|
2190
|
|
|
*/ |
|
2191
|
|
View Code Duplication |
public function isTableOverloaded() |
|
|
|
|
|
|
2192
|
|
|
{ |
|
2193
|
|
|
self::$logger->debug('>>isTableOverloaded()'); |
|
2194
|
|
|
|
|
2195
|
|
|
$reflection = new ReflectionClass($this->BO); |
|
2196
|
|
|
$classname = $reflection->getShortName(); |
|
2197
|
|
|
$tablename = ucfirst($this->BO->getTableName()); |
|
2198
|
|
|
|
|
2199
|
|
|
// use reflection to check to see if we are dealing with a persistent type (e.g. DEnum) which are never overloaded |
|
2200
|
|
|
$implementedInterfaces = $reflection->getInterfaces(); |
|
2201
|
|
|
|
|
2202
|
|
|
foreach ($implementedInterfaces as $interface) { |
|
2203
|
|
|
if ($interface->name == 'Alpha\Model\Type\TypeInterface') { |
|
2204
|
|
|
self::$logger->debug('<<isTableOverloaded [false]'); |
|
2205
|
|
|
|
|
2206
|
|
|
return false; |
|
2207
|
|
|
} |
|
2208
|
|
|
} |
|
2209
|
|
|
|
|
2210
|
|
|
if ($classname != $tablename) { |
|
2211
|
|
|
// loop over all BOs to see if there is one using the same table as this BO |
|
2212
|
|
|
|
|
2213
|
|
|
$BOclasses = ActiveRecord::getBOClassNames(); |
|
2214
|
|
|
|
|
2215
|
|
|
foreach ($BOclasses as $BOclassName) { |
|
2216
|
|
|
$reflection = new ReflectionClass($BOclassName); |
|
2217
|
|
|
$classname = $reflection->getShortName(); |
|
2218
|
|
|
if ($tablename == $classname) { |
|
2219
|
|
|
self::$logger->debug('<<isTableOverloaded [true]'); |
|
2220
|
|
|
|
|
2221
|
|
|
return true; |
|
2222
|
|
|
} |
|
2223
|
|
|
} |
|
2224
|
|
|
self::$logger->debug('<<isTableOverloaded'); |
|
2225
|
|
|
throw new BadTableNameException('The table name ['.$tablename.'] for the class ['.$classname.'] is invalid as it does not match a BO definition in the system!'); |
|
2226
|
|
|
} else { |
|
2227
|
|
|
// check to see if there is already a "classname" column in the database for this BO |
|
2228
|
|
|
$sqlQuery = 'PRAGMA table_info('.$this->BO->getTableName().')'; |
|
2229
|
|
|
$result = self::getConnection()->query($sqlQuery); |
|
2230
|
|
|
$this->BO->setLastQuery($sqlQuery); |
|
2231
|
|
|
|
|
2232
|
|
|
if (!$result) { |
|
2233
|
|
|
self::$logger->warn('Error during pragma table info lookup ['.self::getLastDatabaseError().']'); |
|
2234
|
|
|
} else { |
|
2235
|
|
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) { |
|
2236
|
|
|
if ('classname' == $row['name']) { |
|
2237
|
|
|
self::$logger->debug('<<isTableOverloaded [true]'); |
|
2238
|
|
|
|
|
2239
|
|
|
return true; |
|
2240
|
|
|
} |
|
2241
|
|
|
} |
|
2242
|
|
|
} |
|
2243
|
|
|
|
|
2244
|
|
|
self::$logger->debug('<<isTableOverloaded [false]'); |
|
2245
|
|
|
|
|
2246
|
|
|
return false; |
|
2247
|
|
|
} |
|
2248
|
|
|
} |
|
2249
|
|
|
|
|
2250
|
|
|
/** |
|
2251
|
|
|
* (non-PHPdoc). |
|
2252
|
|
|
* |
|
2253
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::begin() |
|
2254
|
|
|
*/ |
|
2255
|
|
View Code Duplication |
public static function begin() |
|
|
|
|
|
|
2256
|
|
|
{ |
|
2257
|
|
|
if (self::$logger == null) { |
|
2258
|
|
|
self::$logger = new Logger('ActiveRecordProviderSQLite'); |
|
2259
|
|
|
} |
|
2260
|
|
|
self::$logger->debug('>>begin()'); |
|
2261
|
|
|
|
|
2262
|
|
|
if (!self::getConnection()->exec('BEGIN')) { |
|
2263
|
|
|
throw new AlphaException('Error beginning a new transaction, error is ['.self::getLastDatabaseError().']'); |
|
2264
|
|
|
} |
|
2265
|
|
|
|
|
2266
|
|
|
self::$logger->debug('<<begin'); |
|
2267
|
|
|
} |
|
2268
|
|
|
|
|
2269
|
|
|
/** |
|
2270
|
|
|
* (non-PHPdoc). |
|
2271
|
|
|
* |
|
2272
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::commit() |
|
2273
|
|
|
*/ |
|
2274
|
|
View Code Duplication |
public static function commit() |
|
|
|
|
|
|
2275
|
|
|
{ |
|
2276
|
|
|
if (self::$logger == null) { |
|
2277
|
|
|
self::$logger = new Logger('ActiveRecordProviderSQLite'); |
|
2278
|
|
|
} |
|
2279
|
|
|
self::$logger->debug('>>commit()'); |
|
2280
|
|
|
|
|
2281
|
|
|
if (!self::getConnection()->exec('COMMIT')) { |
|
2282
|
|
|
throw new AlphaException('Error commiting a transaction, error is ['.self::getLastDatabaseError().']'); |
|
2283
|
|
|
} |
|
2284
|
|
|
|
|
2285
|
|
|
self::$logger->debug('<<commit'); |
|
2286
|
|
|
} |
|
2287
|
|
|
|
|
2288
|
|
|
/** |
|
2289
|
|
|
* (non-PHPdoc). |
|
2290
|
|
|
* |
|
2291
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::rollback() |
|
2292
|
|
|
*/ |
|
2293
|
|
|
public static function rollback() |
|
2294
|
|
|
{ |
|
2295
|
|
|
if (self::$logger == null) { |
|
2296
|
|
|
self::$logger = new Logger('ActiveRecordProviderSQLite'); |
|
2297
|
|
|
} |
|
2298
|
|
|
|
|
2299
|
|
|
self::$logger->debug('>>rollback()'); |
|
2300
|
|
|
|
|
2301
|
|
|
try { |
|
2302
|
|
|
self::getConnection()->exec('ROLLBACK'); |
|
2303
|
|
|
self::disconnect(); |
|
2304
|
|
|
} catch (Exception $e) { |
|
2305
|
|
|
if (mb_strpos($e->getMessage(), 'cannot rollback - no transaction is active') === false) { // just filtering out errors where the rollback failed due to no current transaction |
|
2306
|
|
|
throw new AlphaException('Error rolling back a transaction, error is ['.self::getLastDatabaseError().']'); |
|
2307
|
|
|
} |
|
2308
|
|
|
} |
|
2309
|
|
|
|
|
2310
|
|
|
self::$logger->debug('<<rollback'); |
|
2311
|
|
|
} |
|
2312
|
|
|
|
|
2313
|
|
|
/** |
|
2314
|
|
|
* (non-PHPdoc). |
|
2315
|
|
|
* |
|
2316
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::setBO() |
|
2317
|
|
|
*/ |
|
2318
|
|
|
public function setBO($BO) |
|
2319
|
|
|
{ |
|
2320
|
|
|
$this->BO = $BO; |
|
2321
|
|
|
} |
|
2322
|
|
|
|
|
2323
|
|
|
/** |
|
2324
|
|
|
* (non-PHPdoc). |
|
2325
|
|
|
* |
|
2326
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::checkDatabaseExists() |
|
2327
|
|
|
*/ |
|
2328
|
|
|
public static function checkDatabaseExists() |
|
2329
|
|
|
{ |
|
2330
|
|
|
$config = ConfigProvider::getInstance(); |
|
2331
|
|
|
|
|
2332
|
|
|
return file_exists($config->get('db.file.path')); |
|
2333
|
|
|
} |
|
2334
|
|
|
|
|
2335
|
|
|
/** |
|
2336
|
|
|
* (non-PHPdoc). |
|
2337
|
|
|
* |
|
2338
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::createDatabase() |
|
2339
|
|
|
*/ |
|
2340
|
|
|
public static function createDatabase() |
|
2341
|
|
|
{ |
|
2342
|
|
|
$config = ConfigProvider::getInstance(); |
|
2343
|
|
|
|
|
2344
|
|
|
if (!self::checkDatabaseExists()) { |
|
2345
|
|
|
fopen($config->get('db.file.path'), 'x+'); |
|
2346
|
|
|
} |
|
2347
|
|
|
} |
|
2348
|
|
|
|
|
2349
|
|
|
/** |
|
2350
|
|
|
* (non-PHPdoc). |
|
2351
|
|
|
* |
|
2352
|
|
|
* @see Alpha\Model\ActiveRecordProviderInterface::dropDatabase() |
|
2353
|
|
|
*/ |
|
2354
|
|
|
public static function dropDatabase() |
|
2355
|
|
|
{ |
|
2356
|
|
|
$config = ConfigProvider::getInstance(); |
|
2357
|
|
|
|
|
2358
|
|
|
if (self::checkDatabaseExists()) { |
|
2359
|
|
|
unlink($config->get('db.file.path')); |
|
2360
|
|
|
} |
|
2361
|
|
|
} |
|
2362
|
|
|
} |
|
2363
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.