1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Alpha\Model; |
4
|
|
|
|
5
|
|
|
use Alpha\Model\Type\Date; |
6
|
|
|
use Alpha\Model\Type\Integer; |
7
|
|
|
use Alpha\Model\Type\Timestamp; |
8
|
|
|
use Alpha\Model\Type\TypeInterface; |
9
|
|
|
use Alpha\Model\Type\Relation; |
10
|
|
|
use Alpha\Util\Config\ConfigProvider; |
11
|
|
|
use Alpha\Util\Logging\Logger; |
12
|
|
|
use Alpha\Util\Service\ServiceFactory; |
13
|
|
|
use Alpha\Exception\AlphaException; |
14
|
|
|
use Alpha\Exception\FailedSaveException; |
15
|
|
|
use Alpha\Exception\FailedDeleteException; |
16
|
|
|
use Alpha\Exception\ValidationException; |
17
|
|
|
use Alpha\Exception\RecordNotFoundException; |
18
|
|
|
use Alpha\Exception\IllegalArguementException; |
19
|
|
|
use Alpha\Exception\NotImplementedException; |
20
|
|
|
use ReflectionClass; |
21
|
|
|
use ReflectionProperty; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Base active record class definition providing database storage via the configured provider. |
25
|
|
|
* |
26
|
|
|
* @since 1.0 |
27
|
|
|
* |
28
|
|
|
* @author John Collins <[email protected]> |
29
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php The BSD License |
30
|
|
|
* @copyright Copyright (c) 2017, John Collins (founder of Alpha Framework). |
31
|
|
|
* All rights reserved. |
32
|
|
|
* |
33
|
|
|
* <pre> |
34
|
|
|
* Redistribution and use in source and binary forms, with or |
35
|
|
|
* without modification, are permitted provided that the |
36
|
|
|
* following conditions are met: |
37
|
|
|
* |
38
|
|
|
* * Redistributions of source code must retain the above |
39
|
|
|
* copyright notice, this list of conditions and the |
40
|
|
|
* following disclaimer. |
41
|
|
|
* * Redistributions in binary form must reproduce the above |
42
|
|
|
* copyright notice, this list of conditions and the |
43
|
|
|
* following disclaimer in the documentation and/or other |
44
|
|
|
* materials provided with the distribution. |
45
|
|
|
* * Neither the name of the Alpha Framework nor the names |
46
|
|
|
* of its contributors may be used to endorse or promote |
47
|
|
|
* products derived from this software without specific |
48
|
|
|
* prior written permission. |
49
|
|
|
* |
50
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
51
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
52
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
53
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
54
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
55
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
56
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
57
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
58
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
60
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
61
|
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
62
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
63
|
|
|
* </pre> |
64
|
|
|
*/ |
65
|
|
|
abstract class ActiveRecord |
66
|
|
|
{ |
67
|
|
|
/** |
68
|
|
|
* The object ID. |
69
|
|
|
* |
70
|
|
|
* @var int |
71
|
|
|
* |
72
|
|
|
* @since 1.0 |
73
|
|
|
*/ |
74
|
|
|
protected $ID; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* The last database query run by this object. Useful for tracing an error. |
78
|
|
|
* |
79
|
|
|
* @var string |
80
|
|
|
* |
81
|
|
|
* @since 1.0 |
82
|
|
|
*/ |
83
|
|
|
protected $lastQuery; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* The version number of the object, used for locking mechanism. |
87
|
|
|
* |
88
|
|
|
* @var \Alpha\Model\Type\Integer |
89
|
|
|
* |
90
|
|
|
* @since 1.0 |
91
|
|
|
*/ |
92
|
|
|
protected $version_num; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* The timestamp of creation. |
96
|
|
|
* |
97
|
|
|
* @var \Alpha\Model\Type\Timestamp |
98
|
|
|
* |
99
|
|
|
* @since 1.0 |
100
|
|
|
*/ |
101
|
|
|
protected $created_ts; |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* The ID of the person who created this record. |
105
|
|
|
* |
106
|
|
|
* @var \Alpha\Model\Type\Integer |
107
|
|
|
* |
108
|
|
|
* @since 1.0 |
109
|
|
|
*/ |
110
|
|
|
protected $created_by; |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* The timestamp of the last update. |
114
|
|
|
* |
115
|
|
|
* @var \Alpha\Model\Type\Timestamp |
116
|
|
|
* |
117
|
|
|
* @since 1.0 |
118
|
|
|
*/ |
119
|
|
|
protected $updated_ts; |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* The ID of the person who last updated this record. |
123
|
|
|
* |
124
|
|
|
* @var \Alpha\Model\Type\Integer |
125
|
|
|
* |
126
|
|
|
* @since 1.0 |
127
|
|
|
*/ |
128
|
|
|
protected $updated_by; |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* An array of the names of all of the default attributes of a persistent Record defined in this class. |
132
|
|
|
* |
133
|
|
|
* @var array |
134
|
|
|
* |
135
|
|
|
* @since 1.0 |
136
|
|
|
*/ |
137
|
|
|
protected $defaultAttributes = array('ID', 'lastQuery', 'version_num', 'dataLabels', 'created_ts', 'created_by', 'updated_ts', 'updated_by', 'defaultAttributes', 'transientAttributes', 'uniqueAttributes', 'TABLE_NAME', 'logger'); |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* An array of the names of all of the transient attributes of a persistent Record which are not saved to the DB. |
141
|
|
|
* |
142
|
|
|
* @var array |
143
|
|
|
* |
144
|
|
|
* @since 1.0 |
145
|
|
|
*/ |
146
|
|
|
protected $transientAttributes = array('lastQuery', 'dataLabels', 'defaultAttributes', 'transientAttributes', 'uniqueAttributes', 'TABLE_NAME', 'logger'); |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* An array of the uniquely-constained attributes of this persistent record. |
150
|
|
|
* |
151
|
|
|
* @var array |
152
|
|
|
* |
153
|
|
|
* @since 1.0 |
154
|
|
|
*/ |
155
|
|
|
protected $uniqueAttributes = array(); |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* An array of the data labels used for displaying class attributes. |
159
|
|
|
* |
160
|
|
|
* @var array |
161
|
|
|
* |
162
|
|
|
* @since 1.0 |
163
|
|
|
*/ |
164
|
|
|
protected $dataLabels = array(); |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Trace logger. |
168
|
|
|
* |
169
|
|
|
* @var \Alpha\Util\Logging\Logger |
170
|
|
|
* |
171
|
|
|
* @since 1.0 |
172
|
|
|
*/ |
173
|
|
|
private static $logger = null; |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Determines if we will maintain a _history table for this record (default is false). |
177
|
|
|
* |
178
|
|
|
* @var bool |
179
|
|
|
* |
180
|
|
|
* @since 1.2 |
181
|
|
|
*/ |
182
|
|
|
private $maintainHistory = false; |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* The constructor which sets up some housekeeping attributes. |
186
|
|
|
* |
187
|
|
|
* @since 1.0 |
188
|
|
|
*/ |
189
|
|
|
public function __construct() |
190
|
|
|
{ |
191
|
|
|
self::$logger = new Logger('ActiveRecord'); |
192
|
|
|
self::$logger->debug('>>__construct()'); |
193
|
|
|
|
194
|
|
|
$config = ConfigProvider::getInstance(); |
195
|
|
|
$sessionProvider = $config->get('session.provider.name'); |
196
|
|
|
$session = ServiceFactory::getInstance($sessionProvider, 'Alpha\Util\Http\Session\SessionProviderInterface'); |
197
|
|
|
|
198
|
|
|
set_exception_handler('Alpha\Util\ErrorHandlers::catchException'); |
199
|
|
|
set_error_handler('Alpha\Util\ErrorHandlers::catchError', $config->get('php.error.log.level')); |
200
|
|
|
|
201
|
|
|
$this->version_num = new Integer(0); |
202
|
|
|
$this->created_ts = new Timestamp(date('Y-m-d H:i:s')); |
203
|
|
|
$person_ID = ($session->get('currentUser') != null ? $session->get('currentUser')->getID() : 0); |
204
|
|
|
$this->created_by = new Integer($person_ID); |
205
|
|
|
$this->updated_ts = new Timestamp(date('Y-m-d H:i:s')); |
206
|
|
|
$this->updated_by = new Integer($person_ID); |
207
|
|
|
|
208
|
|
|
self::$logger->debug('<<__construct'); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Disconnects the current database connection if one exists. |
213
|
|
|
* |
214
|
|
|
* @since 1.0 |
215
|
|
|
*/ |
216
|
|
|
public static function disconnect() |
217
|
|
|
{ |
218
|
|
|
$config = ConfigProvider::getInstance(); |
219
|
|
|
|
220
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
221
|
|
|
$provider->disconnect(); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Returns a 2d array, where each element in the array is another array representing a database row. |
226
|
|
|
* |
227
|
|
|
* @param string $sqlQuery |
228
|
|
|
* |
229
|
|
|
* @return array |
230
|
|
|
* |
231
|
|
|
* @since 1.1 |
232
|
|
|
* |
233
|
|
|
* @throws \Alpha\Exception\CustomQueryException |
234
|
|
|
*/ |
235
|
|
|
public function query($sqlQuery) |
236
|
|
|
{ |
237
|
|
|
self::$logger->debug('>>query(sqlQuery=['.$sqlQuery.'])'); |
238
|
|
|
|
239
|
|
|
$config = ConfigProvider::getInstance(); |
240
|
|
|
|
241
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
242
|
|
|
$provider->setRecord($this); |
243
|
|
|
$result = $provider->query($sqlQuery); |
244
|
|
|
|
245
|
|
|
self::$logger->debug('<<query ['.print_r($result, true).']'); |
246
|
|
|
|
247
|
|
|
return $result; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Populates the child object with the properties retrived from the database for the object $ID. |
252
|
|
|
* |
253
|
|
|
* @param int $ID The object ID of the business object to load. |
254
|
|
|
* @param int $version Optionaly, provide the version to load that version from the [tablename]_history table. |
255
|
|
|
* |
256
|
|
|
* @since 1.0 |
257
|
|
|
* |
258
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
259
|
|
|
*/ |
260
|
|
|
public function load($ID, $version = 0) |
261
|
|
|
{ |
262
|
|
|
self::$logger->debug('>>load(ID=['.$ID.'], version=['.$version.'])'); |
263
|
|
|
|
264
|
|
|
if (method_exists($this, 'before_load_callback')) { |
265
|
|
|
$this->{'before_load_callback'}(); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
$config = ConfigProvider::getInstance(); |
269
|
|
|
|
270
|
|
|
$this->ID = $ID; |
271
|
|
|
|
272
|
|
|
if ($config->get('cache.provider.name') != '' && $this->loadFromCache()) { |
|
|
|
|
273
|
|
|
// Record was found in cache |
274
|
|
|
} else { |
275
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
276
|
|
|
$provider->setRecord($this); |
277
|
|
|
$provider->load($ID, $version); |
278
|
|
|
|
279
|
|
|
if ($config->get('cache.provider.name') != '') { |
280
|
|
|
$this->addToCache(); |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
$this->setEnumOptions(); |
285
|
|
|
|
286
|
|
|
if (method_exists($this, 'after_load_callback')) { |
287
|
|
|
$this->{'after_load_callback'}(); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
self::$logger->debug('<<load'); |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Load all old versions (if any) of this record from the [tablename]_history table. |
295
|
|
|
* |
296
|
|
|
* @param int $ID The object ID of the record to load. |
297
|
|
|
* |
298
|
|
|
* @return array An array containing objects of this type of record object, order by version. |
299
|
|
|
* |
300
|
|
|
* @since 2.0 |
301
|
|
|
* |
302
|
|
|
* @throws \Alpha\Exception\RecordFoundException |
303
|
|
|
*/ |
304
|
|
|
public function loadAllOldVersions($ID) |
305
|
|
|
{ |
306
|
|
|
self::$logger->debug('>>loadAllOldVersions(ID=['.$ID.'])'); |
307
|
|
|
|
308
|
|
|
$config = ConfigProvider::getInstance(); |
309
|
|
|
|
310
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
311
|
|
|
$provider->setRecord($this); |
312
|
|
|
$objects = $provider->loadAllOldVersions($ID); |
313
|
|
|
|
314
|
|
|
self::$logger->debug('<<loadAllOldVersions['.count($objects).']'); |
315
|
|
|
|
316
|
|
|
return $objects; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Populates the child object from the database table by the given attribute value. |
321
|
|
|
* |
322
|
|
|
* @param string $attribute The name of the attribute to load the object by. |
323
|
|
|
* @param string $value The value of the attribute to load the object by. |
324
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type |
325
|
|
|
* @param array $loadAttributes The attributes to load from the database to this object (leave blank to load all attributes) |
326
|
|
|
* |
327
|
|
|
* @since 1.0 |
328
|
|
|
* |
329
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
330
|
|
|
*/ |
331
|
|
|
public function loadByAttribute($attribute, $value, $ignoreClassType = false, $loadAttributes = array()) |
332
|
|
|
{ |
333
|
|
|
self::$logger->debug('>>loadByAttribute(attribute=['.$attribute.'], value=['.$value.'], ignoreClassType=['.$ignoreClassType.'], |
334
|
|
|
loadAttributes=['.var_export($loadAttributes, true).'])'); |
335
|
|
|
|
336
|
|
|
if (method_exists($this, 'before_loadByAttribute_callback')) { |
337
|
|
|
$this->{'before_loadByAttribute_callback'}(); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
$config = ConfigProvider::getInstance(); |
341
|
|
|
|
342
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
343
|
|
|
$provider->setRecord($this); |
344
|
|
|
$provider->loadByAttribute($attribute, $value, $ignoreClassType, $loadAttributes); |
345
|
|
|
|
346
|
|
|
$this->setEnumOptions(); |
347
|
|
|
|
348
|
|
|
if ($config->get('cache.provider.name') != '' && count($loadAttributes) == 0) { // we will only cache fully-populated records |
349
|
|
|
$this->addToCache(); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
if (method_exists($this, 'after_loadByAttribute_callback')) { |
353
|
|
|
$this->{'after_loadByAttribute_callback'}(); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
self::$logger->debug('<<loadByAttribute'); |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* Loads all of the objects of this class into an array which is returned. |
361
|
|
|
* |
362
|
|
|
* @param int $start The start of the SQL LIMIT clause, useful for pagination. |
363
|
|
|
* @param int $limit The amount (limit) of objects to load, useful for pagination. |
364
|
|
|
* @param string $orderBy The name of the field to sort the objects by. |
365
|
|
|
* @param string $order The order to sort the objects by. |
366
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type |
367
|
|
|
* |
368
|
|
|
* @return array An array containing objects of this type of business object. |
369
|
|
|
* |
370
|
|
|
* @since 1.0 |
371
|
|
|
* |
372
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
373
|
|
|
*/ |
374
|
|
|
public function loadAll($start = 0, $limit = 0, $orderBy = 'ID', $order = 'ASC', $ignoreClassType = false) |
375
|
|
|
{ |
376
|
|
|
self::$logger->debug('>>loadAll(start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
377
|
|
|
|
378
|
|
|
if (method_exists($this, 'before_loadAll_callback')) { |
379
|
|
|
$this->{'before_loadAll_callback'}(); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
$config = ConfigProvider::getInstance(); |
383
|
|
|
|
384
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
385
|
|
|
$provider->setRecord($this); |
386
|
|
|
$objects = $provider->loadAll($start, $limit, $orderBy, $order, $ignoreClassType); |
387
|
|
|
|
388
|
|
|
if (method_exists($this, 'after_loadAll_callback')) { |
389
|
|
|
$this->{'after_loadAll_callback'}(); |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
self::$logger->debug('<<loadAll ['.count($objects).']'); |
393
|
|
|
|
394
|
|
|
return $objects; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Loads all of the objects of this class by the specified attribute into an array which is returned. |
399
|
|
|
* |
400
|
|
|
* @param string $attribute The attribute to load the objects by. |
401
|
|
|
* @param string $value The value of the attribute to load the objects by. |
402
|
|
|
* @param int $start The start of the SQL LIMIT clause, useful for pagination. |
403
|
|
|
* @param int $limit The amount (limit) of objects to load, useful for pagination. |
404
|
|
|
* @param string $orderBy The name of the field to sort the objects by. |
405
|
|
|
* @param string $order The order to sort the objects by. |
406
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type. |
407
|
|
|
* @param array $constructorArgs An optional array of contructor arguements to pass to the records that will be generated and returned. Supports a maximum of 5 arguements. |
408
|
|
|
* |
409
|
|
|
* @return array An array containing objects of this type of business object. |
410
|
|
|
* |
411
|
|
|
* @since 1.0 |
412
|
|
|
* |
413
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
414
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
415
|
|
|
*/ |
416
|
|
|
public function loadAllByAttribute($attribute, $value, $start = 0, $limit = 0, $orderBy = 'ID', $order = 'ASC', $ignoreClassType = false, $constructorArgs = array()) |
417
|
|
|
{ |
418
|
|
|
self::$logger->debug('>>loadAllByAttribute(attribute=['.$attribute.'], value=['.$value.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']'); |
419
|
|
|
|
420
|
|
|
if (method_exists($this, 'before_loadAllByAttribute_callback')) { |
421
|
|
|
$this->{'before_loadAllByAttribute_callback'}(); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
$config = ConfigProvider::getInstance(); |
425
|
|
|
|
426
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
427
|
|
|
$provider->setRecord($this); |
428
|
|
|
$objects = $provider->loadAllByAttribute($attribute, $value, $start, $limit, $orderBy, $order, $ignoreClassType); |
429
|
|
|
|
430
|
|
|
if (method_exists($this, 'after_loadAllByAttribute_callback')) { |
431
|
|
|
$this->{'after_loadAllByAttribute_callback'}(); |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
self::$logger->debug('<<loadAllByAttribute ['.count($objects).']'); |
435
|
|
|
|
436
|
|
|
return $objects; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* Loads all of the objects of this class by the specified attributes into an array which is returned. |
441
|
|
|
* |
442
|
|
|
* @param array $attributes The attributes to load the objects by. |
443
|
|
|
* @param array $values The values of the attributes to load the objects by. |
444
|
|
|
* @param int $start The start of the SQL LIMIT clause, useful for pagination. |
445
|
|
|
* @param int $limit The amount (limit) of objects to load, useful for pagination. |
446
|
|
|
* @param string $orderBy The name of the field to sort the objects by. |
447
|
|
|
* @param string $order The order to sort the objects by. |
448
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type |
449
|
|
|
* |
450
|
|
|
* @return array An array containing objects of this type of business object. |
451
|
|
|
* |
452
|
|
|
* @since 1.0 |
453
|
|
|
* |
454
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
455
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
456
|
|
|
*/ |
457
|
|
|
public function loadAllByAttributes($attributes = array(), $values = array(), $start = 0, $limit = 0, $orderBy = 'ID', $order = 'ASC', $ignoreClassType = false) |
458
|
|
|
{ |
459
|
|
|
self::$logger->debug('>>loadAllByAttributes(attributes=['.var_export($attributes, true).'], values=['.var_export($values, true).'], start=['. |
460
|
|
|
$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
461
|
|
|
|
462
|
|
|
if (method_exists($this, 'before_loadAllByAttributes_callback')) { |
463
|
|
|
$this->{'before_loadAllByAttributes_callback'}(); |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
$config = ConfigProvider::getInstance(); |
467
|
|
|
|
468
|
|
|
if (!is_array($attributes) || !is_array($values)) { |
469
|
|
|
throw new IllegalArguementException('Illegal arrays attributes=['.var_export($attributes, true).'] and values=['.var_export($values, true). |
470
|
|
|
'] provided to loadAllByAttributes'); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
474
|
|
|
$provider->setRecord($this); |
475
|
|
|
$objects = $provider->loadAllByAttributes($attributes, $values, $start, $limit, $orderBy, $order, $ignoreClassType); |
476
|
|
|
|
477
|
|
|
if (method_exists($this, 'after_loadAllByAttributes_callback')) { |
478
|
|
|
$this->{'after_loadAllByAttributes_callback'}(); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
self::$logger->debug('<<loadAllByAttributes ['.count($objects).']'); |
482
|
|
|
|
483
|
|
|
return $objects; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* Loads all of the objects of this class that where updated (updated_ts value) on the date indicated. |
488
|
|
|
* |
489
|
|
|
* @param string $date The date for which to load the objects updated on, in the format 'YYYY-MM-DD'. |
490
|
|
|
* @param int $start The start of the SQL LIMIT clause, useful for pagination. |
491
|
|
|
* @param int $limit The amount (limit) of objects to load, useful for pagination. |
492
|
|
|
* @param string $orderBy The name of the field to sort the objects by. |
493
|
|
|
* @param string $order The order to sort the objects by. |
494
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type |
495
|
|
|
* |
496
|
|
|
* @return array An array containing objects of this type of business object. |
497
|
|
|
* |
498
|
|
|
* @since 1.0 |
499
|
|
|
* |
500
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
501
|
|
|
*/ |
502
|
|
|
public function loadAllByDayUpdated($date, $start = 0, $limit = 0, $orderBy = 'ID', $order = 'ASC', $ignoreClassType = false) |
503
|
|
|
{ |
504
|
|
|
self::$logger->debug('>>loadAllByDayUpdated(date=['.$date.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
505
|
|
|
|
506
|
|
|
if (method_exists($this, 'before_loadAllByDayUpdated_callback')) { |
507
|
|
|
$this->{'before_loadAllByDayUpdated_callback'}(); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
$config = ConfigProvider::getInstance(); |
511
|
|
|
|
512
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
513
|
|
|
$provider->setRecord($this); |
514
|
|
|
$objects = $provider->loadAllByDayUpdated($date, $start, $limit, $orderBy, $order, $ignoreClassType); |
515
|
|
|
|
516
|
|
|
if (method_exists($this, 'after_loadAllByDayUpdated_callback')) { |
517
|
|
|
$this->{'after_loadAllByDayUpdated_callback'}(); |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
self::$logger->debug('<<loadAllByDayUpdated ['.count($objects).']'); |
521
|
|
|
|
522
|
|
|
return $objects; |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
/** |
526
|
|
|
* Loads all of the specified attribute values of this class by the specified attribute into an |
527
|
|
|
* array which is returned. |
528
|
|
|
* |
529
|
|
|
* @param string $attribute The attribute name to load the field values by. |
530
|
|
|
* @param string $value The value of the attribute to load the field values by. |
531
|
|
|
* @param string $returnAttribute The name of the attribute to return. |
532
|
|
|
* @param string $order The order to sort the records by. |
533
|
|
|
* @param bool $ignoreClassType Default is false, set to true if you want to load from overloaded tables and ignore the class type. |
534
|
|
|
* |
535
|
|
|
* @return array An array of field values. |
536
|
|
|
* |
537
|
|
|
* @since 1.0 |
538
|
|
|
* |
539
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
540
|
|
|
*/ |
541
|
|
|
public function loadAllFieldValuesByAttribute($attribute, $value, $returnAttribute, $order = 'ASC', $ignoreClassType = false) |
542
|
|
|
{ |
543
|
|
|
self::$logger->debug('>>loadAllFieldValuesByAttribute(attribute=['.$attribute.'], value=['.$value.'], returnAttribute=['.$returnAttribute.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.']'); |
544
|
|
|
|
545
|
|
|
$config = ConfigProvider::getInstance(); |
546
|
|
|
|
547
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
548
|
|
|
$provider->setRecord($this); |
549
|
|
|
$values = $provider->loadAllFieldValuesByAttribute($attribute, $value, $returnAttribute, $order, $ignoreClassType); |
550
|
|
|
|
551
|
|
|
self::$logger->debug('<<loadAllFieldValuesByAttribute ['.count($values).']'); |
552
|
|
|
|
553
|
|
|
return $values; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
/** |
557
|
|
|
* Saves the object. If $this->ID is empty or null it will INSERT, otherwise UPDATE. |
558
|
|
|
* |
559
|
|
|
* @since 1.0 |
560
|
|
|
* |
561
|
|
|
* @throws \Alpha\Exception\FailedSaveException |
562
|
|
|
* @throws \Alpha\Exception\LockingException |
563
|
|
|
* @throws \Alpha\Exception\ValidationException |
564
|
|
|
*/ |
565
|
|
|
public function save() |
566
|
|
|
{ |
567
|
|
|
self::$logger->debug('>>save()'); |
568
|
|
|
|
569
|
|
|
if (method_exists($this, 'before_save_callback')) { |
570
|
|
|
$this->{'before_save_callback'}(); |
571
|
|
|
} |
572
|
|
|
|
573
|
|
|
$config = ConfigProvider::getInstance(); |
574
|
|
|
|
575
|
|
|
// firstly we will validate the object before we try to save it |
576
|
|
|
$this->validate(); |
577
|
|
|
|
578
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
579
|
|
|
$provider->setRecord($this); |
580
|
|
|
$provider->save(); |
581
|
|
|
|
582
|
|
|
if ($config->get('cache.provider.name') != '') { |
583
|
|
|
$this->removeFromCache(); |
584
|
|
|
$this->addToCache(); |
585
|
|
|
} |
586
|
|
|
|
587
|
|
|
if (method_exists($this, 'after_save_callback')) { |
588
|
|
|
$this->{'after_save_callback'}(); |
589
|
|
|
} |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* Saves the field specified with the value supplied. Only works for persistent records. Note that no Alpha type |
594
|
|
|
* validation is performed with this method! |
595
|
|
|
* |
596
|
|
|
* @param string $attribute The name of the attribute to save. |
597
|
|
|
* @param mixed $value The value of the attribute to save. |
598
|
|
|
* |
599
|
|
|
* @since 1.0 |
600
|
|
|
* |
601
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
602
|
|
|
* @throws \Alpha\Exception\FailedSaveException |
603
|
|
|
*/ |
604
|
|
|
public function saveAttribute($attribute, $value) |
605
|
|
|
{ |
606
|
|
|
self::$logger->debug('>>saveAttribute(attribute=['.$attribute.'], value=['.$value.'])'); |
607
|
|
|
|
608
|
|
|
if (method_exists($this, 'before_saveAttribute_callback')) { |
609
|
|
|
$this->{'before_saveAttribute_callback'}(); |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
$config = ConfigProvider::getInstance(); |
613
|
|
|
|
614
|
|
|
if (!isset($this->$attribute)) { |
615
|
|
|
throw new IllegalArguementException('Could not perform save, as the attribute ['.$attribute.'] is not present on the class['.get_class($this).']'); |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
if ($this->isTransient()) { |
619
|
|
|
throw new FailedSaveException('Cannot perform saveAttribute method on transient record!'); |
620
|
|
|
} |
621
|
|
|
|
622
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
623
|
|
|
$provider->setRecord($this); |
624
|
|
|
$provider->saveAttribute($attribute, $value); |
625
|
|
|
|
626
|
|
|
if ($config->get('cache.provider.name') != '') { |
627
|
|
|
$this->removeFromCache(); |
628
|
|
|
$this->addToCache(); |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
if (method_exists($this, 'after_saveAttribute_callback')) { |
632
|
|
|
$this->{'after_saveAttribute_callback'}(); |
633
|
|
|
} |
634
|
|
|
|
635
|
|
|
self::$logger->debug('<<saveAttribute'); |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
/** |
639
|
|
|
* Saves the history of the object in the [tablename]_history table. It will always perform an insert. |
640
|
|
|
* |
641
|
|
|
* @since 1.2 |
642
|
|
|
* |
643
|
|
|
* @throws \Alpha\Exception\FailedSaveException |
644
|
|
|
*/ |
645
|
|
|
public function saveHistory() |
646
|
|
|
{ |
647
|
|
|
self::$logger->debug('>>saveHistory()'); |
648
|
|
|
|
649
|
|
|
if (method_exists($this, 'before_saveHistory_callback')) { |
650
|
|
|
$this->{'before_saveHistory_callback'}(); |
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
$config = ConfigProvider::getInstance(); |
654
|
|
|
|
655
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
656
|
|
|
$provider->setRecord($this); |
657
|
|
|
$provider->saveHistory(); |
658
|
|
|
|
659
|
|
|
if (method_exists($this, 'after_saveHistory_callback')) { |
660
|
|
|
$this->{'after_saveHistory_callback'}(); |
661
|
|
|
} |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
/** |
665
|
|
|
* Validates the object to be saved. |
666
|
|
|
* |
667
|
|
|
* @since 1.0 |
668
|
|
|
* |
669
|
|
|
* @throws \Alpha\Exception\ValidationException |
670
|
|
|
*/ |
671
|
|
|
protected function validate() |
672
|
|
|
{ |
673
|
|
|
self::$logger->debug('>>validate()'); |
674
|
|
|
|
675
|
|
|
if (method_exists($this, 'before_validate_callback')) { |
676
|
|
|
$this->{'before_validate_callback'}(); |
677
|
|
|
} |
678
|
|
|
|
679
|
|
|
// get the class attributes |
680
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
681
|
|
|
$properties = $reflection->getProperties(); |
682
|
|
|
|
683
|
|
|
foreach ($properties as $propObj) { |
684
|
|
|
$propName = $propObj->name; |
685
|
|
|
if (!in_array($propName, $this->defaultAttributes) && !in_array($propName, $this->transientAttributes)) { |
686
|
|
|
$propClass = new ReflectionClass($this->getPropObject($propName)); |
687
|
|
|
$propClass = $propClass->getShortname(); |
688
|
|
|
if (mb_strtoupper($propClass) != 'ENUM' && |
689
|
|
|
mb_strtoupper($propClass) != 'DENUM' && |
690
|
|
|
mb_strtoupper($propClass) != 'DENUMITEM' && |
691
|
|
|
mb_strtoupper($propClass) != 'BOOLEAN') { |
692
|
|
|
if ($this->getPropObject($propName) != false && !preg_match($this->getPropObject($propName)->getRule(), $this->getPropObject($propName)->getValue())) { |
|
|
|
|
693
|
|
|
self::$logger->debug('<<validate'); |
694
|
|
|
throw new ValidationException('Failed to save, validation error is: '.$this->getPropObject($propName)->getHelper()); |
695
|
|
|
} |
696
|
|
|
} |
697
|
|
|
} |
698
|
|
|
} |
699
|
|
|
|
700
|
|
|
if (method_exists($this, 'after_validate_callback')) { |
701
|
|
|
$this->{'after_validate_callback'}(); |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
self::$logger->debug('<<validate'); |
705
|
|
|
} |
706
|
|
|
|
707
|
|
|
/** |
708
|
|
|
* Deletes the current object from the database. |
709
|
|
|
* |
710
|
|
|
* @since 1.0 |
711
|
|
|
* |
712
|
|
|
* @throws \Alpha\Exception\FailedDeleteException |
713
|
|
|
*/ |
714
|
|
|
public function delete() |
715
|
|
|
{ |
716
|
|
|
self::$logger->debug('>>delete()'); |
717
|
|
|
|
718
|
|
|
if (method_exists($this, 'before_delete_callback')) { |
719
|
|
|
$this->{'before_delete_callback'}(); |
720
|
|
|
} |
721
|
|
|
|
722
|
|
|
$config = ConfigProvider::getInstance(); |
723
|
|
|
|
724
|
|
|
// get the class attributes |
725
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
726
|
|
|
$properties = $reflection->getProperties(); |
727
|
|
|
|
728
|
|
|
// check for any relations on this object, then remove them to prevent orphaned data |
729
|
|
|
foreach ($properties as $propObj) { |
730
|
|
|
$propName = $propObj->name; |
731
|
|
|
|
732
|
|
|
if (!$propObj->isPrivate() && isset($this->$propName) && $this->$propName instanceof Relation) { |
733
|
|
|
$prop = $this->getPropObject($propName); |
734
|
|
|
|
735
|
|
|
// Handle MANY-TO-MANY rels |
736
|
|
|
if ($prop->getRelationType() == 'MANY-TO-MANY') { |
737
|
|
|
self::$logger->debug('Deleting MANY-TO-MANY lookup objects...'); |
738
|
|
|
|
739
|
|
|
try { |
740
|
|
|
// check to see if the rel is on this class |
741
|
|
|
$side = $prop->getSide(get_class($this)); |
742
|
|
|
} catch (IllegalArguementException $iae) { |
743
|
|
|
$side = $prop->getSide(get_parent_class($this)); |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
self::$logger->debug('Side is ['.$side.']'.$this->getID()); |
747
|
|
|
|
748
|
|
|
$lookUp = $prop->getLookup(); |
749
|
|
|
self::$logger->debug('Lookup object['.var_export($lookUp, true).']'); |
750
|
|
|
|
751
|
|
|
// delete all of the old RelationLookup objects for this rel |
752
|
|
|
if ($side == 'left') { |
753
|
|
|
$lookUp->deleteAllByAttribute('leftID', $this->getID()); |
754
|
|
|
} else { |
755
|
|
|
$lookUp->deleteAllByAttribute('rightID', $this->getID()); |
756
|
|
|
} |
757
|
|
|
self::$logger->debug('...done deleting!'); |
758
|
|
|
} |
759
|
|
|
|
760
|
|
|
// should set related field values to null (MySQL is doing this for us as-is) |
761
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY' && !$prop->getRelatedClass() == 'Alpha\Model\Tag') { |
762
|
|
|
$relatedObjects = $prop->getRelated(); |
763
|
|
|
|
764
|
|
|
foreach ($relatedObjects as $object) { |
765
|
|
|
$object->set($prop->getRelatedClassField(), null); |
766
|
|
|
$object->save(); |
767
|
|
|
} |
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
// in the case of tags, we will always remove the related tags once the Record is deleted |
771
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY' && $prop->getRelatedClass() == 'Alpha\Model\Tag') { |
772
|
|
|
// just making sure that the Relation is set to current ID as its transient |
773
|
|
|
$prop->setValue($this->getID()); |
774
|
|
|
$relatedObjects = $prop->getRelated(); |
775
|
|
|
|
776
|
|
|
foreach ($relatedObjects as $object) { |
777
|
|
|
$object->delete(); |
778
|
|
|
} |
779
|
|
|
} |
780
|
|
|
} |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
784
|
|
|
$provider->setRecord($this); |
785
|
|
|
$provider->delete(); |
786
|
|
|
|
787
|
|
|
if ($config->get('cache.provider.name') != '') { |
788
|
|
|
$this->removeFromCache(); |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
if (method_exists($this, 'after_delete_callback')) { |
792
|
|
|
$this->{'after_delete_callback'}(); |
793
|
|
|
} |
794
|
|
|
|
795
|
|
|
$this->clear(); |
796
|
|
|
self::$logger->debug('<<delete'); |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
/** |
800
|
|
|
* Delete all object instances from the database by the specified attribute matching the value provided. |
801
|
|
|
* |
802
|
|
|
* @param string $attribute The name of the field to delete the objects by. |
803
|
|
|
* @param mixed $value The value of the field to delete the objects by. |
804
|
|
|
* |
805
|
|
|
* @return int The number of rows deleted. |
806
|
|
|
* |
807
|
|
|
* @since 1.0 |
808
|
|
|
* |
809
|
|
|
* @throws \Alpha\Exception\FailedDeleteException |
810
|
|
|
*/ |
811
|
|
|
public function deleteAllByAttribute($attribute, $value) |
812
|
|
|
{ |
813
|
|
|
self::$logger->debug('>>deleteAllByAttribute(attribute=['.$attribute.'], value=['.$value.'])'); |
814
|
|
|
|
815
|
|
|
if (method_exists($this, 'before_deleteAllByAttribute_callback')) { |
816
|
|
|
$this->{'before_deleteAllByAttribute_callback'}(); |
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
try { |
820
|
|
|
$doomedObjects = $this->loadAllByAttribute($attribute, $value); |
821
|
|
|
$deletedRowCount = 0; |
822
|
|
|
|
823
|
|
|
foreach ($doomedObjects as $object) { |
824
|
|
|
$object->delete(); |
825
|
|
|
++$deletedRowCount; |
826
|
|
|
} |
827
|
|
|
} catch (RecordNotFoundException $bonf) { |
828
|
|
|
// nothing found to delete |
829
|
|
|
self::$logger->warn($bonf->getMessage()); |
830
|
|
|
|
831
|
|
|
return 0; |
832
|
|
|
} catch (AlphaException $e) { |
833
|
|
|
self::$logger->debug('<<deleteAllByAttribute [0]'); |
834
|
|
|
throw new FailedDeleteException('Failed to delete objects, error is ['.$e->getMessage().']'); |
835
|
|
|
} |
836
|
|
|
|
837
|
|
|
if (method_exists($this, 'after_deleteAllByAttribute_callback')) { |
838
|
|
|
$this->{'after_deleteAllByAttribute_callback'}(); |
839
|
|
|
} |
840
|
|
|
|
841
|
|
|
self::$logger->debug('<<deleteAllByAttribute ['.$deletedRowCount.']'); |
842
|
|
|
|
843
|
|
|
return $deletedRowCount; |
844
|
|
|
} |
845
|
|
|
|
846
|
|
|
/** |
847
|
|
|
* Gets the version_num of the object from the database (returns 0 if the Record is not saved yet). |
848
|
|
|
* |
849
|
|
|
* @return int |
850
|
|
|
* |
851
|
|
|
* @since 1.0 |
852
|
|
|
* |
853
|
|
|
* @throws \Alpha\Exception\RecordNotFoundException |
854
|
|
|
*/ |
855
|
|
|
public function getVersion() |
856
|
|
|
{ |
857
|
|
|
self::$logger->debug('>>getVersion()'); |
858
|
|
|
|
859
|
|
|
if (method_exists($this, 'before_getVersion_callback')) { |
860
|
|
|
$this->{'before_getVersion_callback'}(); |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
$config = ConfigProvider::getInstance(); |
864
|
|
|
|
865
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
866
|
|
|
$provider->setRecord($this); |
867
|
|
|
$ver = $provider->getVersion(); |
868
|
|
|
|
869
|
|
|
if (method_exists($this, 'after_getVersion_callback')) { |
870
|
|
|
$this->{'after_getVersion_callback'}(); |
871
|
|
|
} |
872
|
|
|
|
873
|
|
|
self::$logger->debug('<<getVersion ['.$ver.']'); |
874
|
|
|
|
875
|
|
|
return $ver; |
876
|
|
|
} |
877
|
|
|
|
878
|
|
|
/** |
879
|
|
|
* Builds a new database table for the Record class. |
880
|
|
|
* |
881
|
|
|
* @since 1.0 |
882
|
|
|
* |
883
|
|
|
* @throws \Alpha\Exception\AlphaException |
884
|
|
|
*/ |
885
|
|
|
public function makeTable() |
886
|
|
|
{ |
887
|
|
|
self::$logger->debug('>>makeTable()'); |
888
|
|
|
|
889
|
|
|
if (method_exists($this, 'before_makeTable_callback')) { |
890
|
|
|
$this->{'before_makeTable_callback'}(); |
891
|
|
|
} |
892
|
|
|
|
893
|
|
|
$config = ConfigProvider::getInstance(); |
894
|
|
|
|
895
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
896
|
|
|
$provider->setRecord($this); |
897
|
|
|
$provider->makeTable(); |
898
|
|
|
|
899
|
|
|
if (method_exists($this, 'after_makeTable_callback')) { |
900
|
|
|
$this->{'after_makeTable_callback'}(); |
901
|
|
|
} |
902
|
|
|
|
903
|
|
|
self::$logger->info('Successfully created the table ['.$this->getTableName().'] for the class ['.get_class($this).']'); |
904
|
|
|
|
905
|
|
|
self::$logger->debug('<<makeTable'); |
906
|
|
|
} |
907
|
|
|
|
908
|
|
|
/** |
909
|
|
|
* Builds a new database table for the Record class to story it's history of changes. |
910
|
|
|
* |
911
|
|
|
* @since 1.2 |
912
|
|
|
* |
913
|
|
|
* @throws \Alpha\Exception\AlphaException |
914
|
|
|
*/ |
915
|
|
|
public function makeHistoryTable() |
916
|
|
|
{ |
917
|
|
|
self::$logger->debug('>>makeHistoryTable()'); |
918
|
|
|
|
919
|
|
|
if (method_exists($this, 'before_makeHistoryTable_callback')) { |
920
|
|
|
$this->{'before_makeHistoryTable_callback'}(); |
921
|
|
|
} |
922
|
|
|
|
923
|
|
|
$config = ConfigProvider::getInstance(); |
924
|
|
|
|
925
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
926
|
|
|
$provider->setRecord($this); |
927
|
|
|
$provider->makeHistoryTable(); |
928
|
|
|
|
929
|
|
|
if (method_exists($this, 'after_makeHistoryTable_callback')) { |
930
|
|
|
$this->{'after_makeHistoryTable_callback'}(); |
931
|
|
|
} |
932
|
|
|
|
933
|
|
|
self::$logger->info('Successfully created the table ['.$this->getTableName().'_history] for the class ['.get_class($this).']'); |
934
|
|
|
|
935
|
|
|
self::$logger->debug('<<makeHistoryTable'); |
936
|
|
|
} |
937
|
|
|
|
938
|
|
|
/** |
939
|
|
|
* Re-builds the table if the model requirements have changed. All data is lost! |
940
|
|
|
* |
941
|
|
|
* @since 1.0 |
942
|
|
|
* |
943
|
|
|
* @throws \Alpha\Exception\AlphaException |
944
|
|
|
*/ |
945
|
|
|
public function rebuildTable() |
946
|
|
|
{ |
947
|
|
|
self::$logger->debug('>>rebuildTable()'); |
948
|
|
|
|
949
|
|
|
if (method_exists($this, 'before_rebuildTable_callback')) { |
950
|
|
|
$this->{'before_rebuildTable_callback'}(); |
951
|
|
|
} |
952
|
|
|
|
953
|
|
|
$config = ConfigProvider::getInstance(); |
954
|
|
|
|
955
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
956
|
|
|
$provider->setRecord($this); |
957
|
|
|
$provider->rebuildTable(); |
958
|
|
|
|
959
|
|
|
if (method_exists($this, 'after_rebuildTable_callback')) { |
960
|
|
|
$this->{'after_rebuildTable_callback'}(); |
961
|
|
|
} |
962
|
|
|
|
963
|
|
|
self::$logger->debug('<<rebuildTable'); |
964
|
|
|
} |
965
|
|
|
|
966
|
|
|
/** |
967
|
|
|
* Drops the table if the model requirements have changed. All data is lost! |
968
|
|
|
* |
969
|
|
|
* @since 1.0 |
970
|
|
|
* |
971
|
|
|
* @param string $tableName Optional table name, leave blank for the defined table for this class to be dropped |
972
|
|
|
* |
973
|
|
|
* @throws \Alpha\Exception\AlphaException |
974
|
|
|
*/ |
975
|
|
|
public function dropTable($tableName = null) |
976
|
|
|
{ |
977
|
|
|
self::$logger->debug('>>dropTable()'); |
978
|
|
|
|
979
|
|
|
if (method_exists($this, 'before_dropTable_callback')) { |
980
|
|
|
$this->{'before_dropTable_callback'}(); |
981
|
|
|
} |
982
|
|
|
|
983
|
|
|
$config = ConfigProvider::getInstance(); |
984
|
|
|
|
985
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
986
|
|
|
$provider->setRecord($this); |
987
|
|
|
$provider->dropTable($tableName); |
988
|
|
|
|
989
|
|
|
if (method_exists($this, 'after_dropTable_callback')) { |
990
|
|
|
$this->{'after_dropTable_callback'}(); |
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
self::$logger->debug('<<dropTable'); |
994
|
|
|
} |
995
|
|
|
|
996
|
|
|
/** |
997
|
|
|
* Adds in a new class property without loosing existing data (does an ALTER TABLE query on the |
998
|
|
|
* database). |
999
|
|
|
* |
1000
|
|
|
* @param string $propName The name of the new field to add to the database table. |
1001
|
|
|
* |
1002
|
|
|
* @since 1.0 |
1003
|
|
|
* |
1004
|
|
|
* @throws \Alpha\Exception\AlphaException |
1005
|
|
|
*/ |
1006
|
|
|
public function addProperty($propName) |
1007
|
|
|
{ |
1008
|
|
|
self::$logger->debug('>>addProperty(propName=['.$propName.'])'); |
1009
|
|
|
|
1010
|
|
|
$config = ConfigProvider::getInstance(); |
1011
|
|
|
|
1012
|
|
|
if (method_exists($this, 'before_addProperty_callback')) { |
1013
|
|
|
$this->{'before_addProperty_callback'}(); |
1014
|
|
|
} |
1015
|
|
|
|
1016
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1017
|
|
|
$provider->setRecord($this); |
1018
|
|
|
$provider->addProperty($propName); |
1019
|
|
|
|
1020
|
|
|
if (method_exists($this, 'after_addProperty_callback')) { |
1021
|
|
|
$this->{'after_addProperty_callback'}(); |
1022
|
|
|
} |
1023
|
|
|
|
1024
|
|
|
self::$logger->debug('<<addProperty'); |
1025
|
|
|
} |
1026
|
|
|
|
1027
|
|
|
/** |
1028
|
|
|
* Populates the current business object from the provided hash array. |
1029
|
|
|
* |
1030
|
|
|
* @param array $hashArray |
1031
|
|
|
* |
1032
|
|
|
* @since 1.2.1 |
1033
|
|
|
*/ |
1034
|
|
|
public function populateFromArray($hashArray) |
1035
|
|
|
{ |
1036
|
|
|
self::$logger->debug('>>populateFromArray(hashArray=['.print_r($hashArray, true).'])'); |
1037
|
|
|
|
1038
|
|
|
// get the class attributes |
1039
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
1040
|
|
|
$properties = $reflection->getProperties(); |
1041
|
|
|
|
1042
|
|
|
foreach ($properties as $propObj) { |
1043
|
|
|
$propName = $propObj->name; |
1044
|
|
|
|
1045
|
|
|
if (isset($hashArray[$propName])) { |
1046
|
|
|
if ($this->getPropObject($propName) instanceof Date || $this->getPropObject($propName) instanceof Timestamp) { |
1047
|
|
|
$this->getPropObject($propName)->populateFromString($hashArray[$propName]); |
1048
|
|
|
} elseif ($this->getPropObject($propName) instanceof TypeInterface) { |
1049
|
|
|
$this->getPropObject($propName)->setValue($hashArray[$propName]); |
1050
|
|
|
} |
1051
|
|
|
|
1052
|
|
|
if ($propName == 'version_num' && isset($hashArray['version_num'])) { |
1053
|
|
|
$this->version_num->setValue($hashArray['version_num']); |
1054
|
|
|
} |
1055
|
|
|
|
1056
|
|
|
if ($this->getPropObject($propName) instanceof Relation) { |
1057
|
|
|
$rel = $this->getPropObject($propName); |
1058
|
|
|
|
1059
|
|
|
if ($rel->getRelationType() == 'MANY-TO-MANY') { |
1060
|
|
|
$IDs = explode(',', $hashArray[$propName]); |
1061
|
|
|
$rel->setRelatedIDs($IDs); |
1062
|
|
|
$this->$propName = $rel; |
1063
|
|
|
} |
1064
|
|
|
} |
1065
|
|
|
} |
1066
|
|
|
} |
1067
|
|
|
|
1068
|
|
|
self::$logger->debug('<<populateFromArray'); |
1069
|
|
|
} |
1070
|
|
|
|
1071
|
|
|
/** |
1072
|
|
|
* Gets the maximum ID value from the database for this class type. |
1073
|
|
|
* |
1074
|
|
|
* @return int The maximum ID value in the class table. |
1075
|
|
|
* |
1076
|
|
|
* @since 1.0 |
1077
|
|
|
* |
1078
|
|
|
* @throws \Alpha\Exception\AlphaException |
1079
|
|
|
*/ |
1080
|
|
|
public function getMAX() |
1081
|
|
|
{ |
1082
|
|
|
self::$logger->debug('>>getMAX()'); |
1083
|
|
|
|
1084
|
|
|
if (method_exists($this, 'before_getMAX_callback')) { |
1085
|
|
|
$this->{'before_getMAX_callback'}(); |
1086
|
|
|
} |
1087
|
|
|
|
1088
|
|
|
$config = ConfigProvider::getInstance(); |
1089
|
|
|
|
1090
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1091
|
|
|
$provider->setRecord($this); |
1092
|
|
|
$max = $provider->getMAX(); |
1093
|
|
|
|
1094
|
|
|
if (method_exists($this, 'after_getMAX_callback')) { |
1095
|
|
|
$this->{'after_getMAX_callback'}(); |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
self::$logger->debug('<<getMAX ['.$max.']'); |
1099
|
|
|
|
1100
|
|
|
return $max; |
1101
|
|
|
} |
1102
|
|
|
|
1103
|
|
|
/** |
1104
|
|
|
* Gets the count from the database for the amount of objects of this class. |
1105
|
|
|
* |
1106
|
|
|
* @param array $attributes The attributes to count the objects by (optional). |
1107
|
|
|
* @param array $values The values of the attributes to count the objects by (optional). |
1108
|
|
|
* |
1109
|
|
|
* @return int |
1110
|
|
|
* |
1111
|
|
|
* @since 1.0 |
1112
|
|
|
* |
1113
|
|
|
* @throws \Alpha\Exception\AlphaException |
1114
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
1115
|
|
|
*/ |
1116
|
|
|
public function getCount($attributes = array(), $values = array()) |
1117
|
|
|
{ |
1118
|
|
|
self::$logger->debug('>>getCount(attributes=['.var_export($attributes, true).'], values=['.var_export($values, true).'])'); |
1119
|
|
|
|
1120
|
|
|
if (method_exists($this, 'before_getCount_callback')) { |
1121
|
|
|
$this->{'before_getCount_callback'}(); |
1122
|
|
|
} |
1123
|
|
|
|
1124
|
|
|
$config = ConfigProvider::getInstance(); |
1125
|
|
|
|
1126
|
|
|
if (!is_array($attributes) || !is_array($values)) { |
1127
|
|
|
throw new IllegalArguementException('Illegal arrays attributes=['.var_export($attributes, true).'] and values=['.var_export($values, true).'] provided to loadAllByAttributes'); |
1128
|
|
|
} |
1129
|
|
|
|
1130
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1131
|
|
|
$provider->setRecord($this); |
1132
|
|
|
$count = $provider->getCount($attributes, $values); |
1133
|
|
|
|
1134
|
|
|
if (method_exists($this, 'after_getCount_callback')) { |
1135
|
|
|
$this->{'after_getCount_callback'}(); |
1136
|
|
|
} |
1137
|
|
|
|
1138
|
|
|
self::$logger->debug('<<getCount ['.$count.']'); |
1139
|
|
|
|
1140
|
|
|
return $count; |
1141
|
|
|
} |
1142
|
|
|
|
1143
|
|
|
/** |
1144
|
|
|
* Gets the count from the database for the amount of entries in the [tableName]_history table for this business object. Only call |
1145
|
|
|
* this method on classes where maintainHistory = true, otherwise an exception will be thrown. |
1146
|
|
|
* |
1147
|
|
|
* @return int |
1148
|
|
|
* |
1149
|
|
|
* @since 1.2 |
1150
|
|
|
* |
1151
|
|
|
* @throws \Alpha\Exception\AlphaException |
1152
|
|
|
*/ |
1153
|
|
|
public function getHistoryCount() |
1154
|
|
|
{ |
1155
|
|
|
self::$logger->debug('>>getHistoryCount()'); |
1156
|
|
|
|
1157
|
|
|
if (method_exists($this, 'before_getHistoryCount_callback')) { |
1158
|
|
|
$this->{'before_getHistoryCount_callback'}(); |
1159
|
|
|
} |
1160
|
|
|
|
1161
|
|
|
$config = ConfigProvider::getInstance(); |
1162
|
|
|
|
1163
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1164
|
|
|
$provider->setRecord($this); |
1165
|
|
|
$count = $provider->getHistoryCount(); |
1166
|
|
|
|
1167
|
|
|
if (method_exists($this, 'after_getHistoryCount_callback')) { |
1168
|
|
|
$this->{'after_getHistoryCount_callback'}(); |
1169
|
|
|
} |
1170
|
|
|
|
1171
|
|
|
self::$logger->debug('<<getHistoryCount ['.$count.']'); |
1172
|
|
|
|
1173
|
|
|
return $count; |
1174
|
|
|
} |
1175
|
|
|
|
1176
|
|
|
/** |
1177
|
|
|
* Gets the ID for the object in zero-padded format (same as getID()). |
1178
|
|
|
* |
1179
|
|
|
* @return string 11 digit zero-padded ID value. |
1180
|
|
|
* |
1181
|
|
|
* @since 1.0 |
1182
|
|
|
*/ |
1183
|
|
|
final public function getID() |
1184
|
|
|
{ |
1185
|
|
|
if (self::$logger == null) { |
1186
|
|
|
self::$logger = new Logger('ActiveRecord'); |
1187
|
|
|
} |
1188
|
|
|
self::$logger->debug('>>getID()'); |
1189
|
|
|
$oid = str_pad($this->ID, 11, '0', STR_PAD_LEFT); |
1190
|
|
|
self::$logger->debug('<<getID ['.$oid.']'); |
1191
|
|
|
|
1192
|
|
|
return $oid; |
1193
|
|
|
} |
1194
|
|
|
|
1195
|
|
|
/** |
1196
|
|
|
* Method for getting version number of the object. |
1197
|
|
|
* |
1198
|
|
|
* @return \Alpha\Model\Type\Integer The object version number. |
1199
|
|
|
* |
1200
|
|
|
* @since 1.0 |
1201
|
|
|
*/ |
1202
|
|
|
public function getVersionNumber() |
1203
|
|
|
{ |
1204
|
|
|
self::$logger->debug('>>getVersionNumber()'); |
1205
|
|
|
self::$logger->debug('<<getVersionNumber ['.$this->version_num.']'); |
1206
|
|
|
|
1207
|
|
|
return $this->version_num; |
1208
|
|
|
} |
1209
|
|
|
|
1210
|
|
|
/** |
1211
|
|
|
* Populate all of the enum options for this object from the database. |
1212
|
|
|
* |
1213
|
|
|
* @since 1.0 |
1214
|
|
|
* |
1215
|
|
|
* @throws \Alpha\Exception\AlphaException |
1216
|
|
|
*/ |
1217
|
|
|
protected function setEnumOptions() |
1218
|
|
|
{ |
1219
|
|
|
self::$logger->debug('>>setEnumOptions()'); |
1220
|
|
|
|
1221
|
|
|
if (method_exists($this, 'before_setEnumOptions_callback')) { |
1222
|
|
|
$this->{'before_setEnumOptions_callback'}(); |
1223
|
|
|
} |
1224
|
|
|
|
1225
|
|
|
$config = ConfigProvider::getInstance(); |
1226
|
|
|
|
1227
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1228
|
|
|
$provider->setRecord($this); |
1229
|
|
|
try { |
1230
|
|
|
$provider->setEnumOptions(); |
1231
|
|
|
} catch (NotImplementedException $e) { |
1232
|
|
|
self::$logger->debug($e->getMessage()); |
1233
|
|
|
} |
1234
|
|
|
|
1235
|
|
|
self::$logger->debug('<<setEnumOptions'); |
1236
|
|
|
} |
1237
|
|
|
|
1238
|
|
|
/** |
1239
|
|
|
* Generic getter method for accessing class properties. Will use the method get.ucfirst($prop) instead if that |
1240
|
|
|
* method exists at a child level (by default). Set $noChildMethods to true if you don't want to use any |
1241
|
|
|
* get.ucfirst($prop) method even if it exists, false otherwise (default). |
1242
|
|
|
* |
1243
|
|
|
* @param string $prop The name of the object property to get. |
1244
|
|
|
* @param bool $noChildMethods Set to true if you do not want to use getters in the child object, defaults to false. |
1245
|
|
|
* |
1246
|
|
|
* @return mixed The property value. |
1247
|
|
|
* |
1248
|
|
|
* @since 1.0 |
1249
|
|
|
* |
1250
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
1251
|
|
|
* @throws \Alpha\Exception\AlphaException |
1252
|
|
|
*/ |
1253
|
|
|
public function get($prop, $noChildMethods = false) |
1254
|
|
|
{ |
1255
|
|
|
if (self::$logger == null) { |
1256
|
|
|
self::$logger = new Logger('ActiveRecord'); |
1257
|
|
|
} |
1258
|
|
|
|
1259
|
|
|
self::$logger->debug('>>get(prop=['.$prop.'], noChildMethods=['.$noChildMethods.'])'); |
1260
|
|
|
|
1261
|
|
|
if (method_exists($this, 'before_get_callback')) { |
1262
|
|
|
$this->{'before_get_callback'}(); |
1263
|
|
|
} |
1264
|
|
|
|
1265
|
|
|
if (empty($prop)) { |
1266
|
|
|
throw new IllegalArguementException('Cannot call get with empty $prop arguement!'); |
1267
|
|
|
} |
1268
|
|
|
|
1269
|
|
|
// handle attributes with a get.ucfirst($prop) method |
1270
|
|
|
if (!$noChildMethods && method_exists($this, 'get'.ucfirst($prop))) { |
1271
|
|
|
if (method_exists($this, 'after_get_callback')) { |
1272
|
|
|
$this->{'after_get_callback'}(); |
1273
|
|
|
} |
1274
|
|
|
|
1275
|
|
|
$methodName = 'get'.ucfirst($prop); |
1276
|
|
|
|
1277
|
|
|
self::$logger->debug('<<get ['.print_r($this->$methodName(), true).'])'); |
1278
|
|
|
|
1279
|
|
|
return $this->$methodName(); |
1280
|
|
|
} else { |
1281
|
|
|
// handle attributes with no dedicated child get.ucfirst($prop) method |
1282
|
|
|
if (isset($this->$prop) && is_object($this->$prop) && method_exists($this->$prop, 'getValue')) { |
1283
|
|
|
if (method_exists($this, 'after_get_callback')) { |
1284
|
|
|
$this->{'after_get_callback'}(); |
1285
|
|
|
} |
1286
|
|
|
|
1287
|
|
|
// complex types will have a getValue() method, return the value of that |
1288
|
|
|
self::$logger->debug('<<get ['.$this->$prop->getValue().'])'); |
1289
|
|
|
|
1290
|
|
|
return $this->$prop->getValue(); |
1291
|
|
|
} elseif (isset($this->$prop)) { |
1292
|
|
|
if (method_exists($this, 'after_get_callback')) { |
1293
|
|
|
$this->{'after_get_callback'}(); |
1294
|
|
|
} |
1295
|
|
|
|
1296
|
|
|
// simple types returned as-is |
1297
|
|
|
self::$logger->debug('<<get ['.print_r($this->$prop, true).'])'); |
1298
|
|
|
|
1299
|
|
|
return $this->$prop; |
1300
|
|
|
} else { |
1301
|
|
|
self::$logger->debug('<<get'); |
1302
|
|
|
throw new AlphaException('Could not access the property ['.$prop.'] on the object of class ['.get_class($this).']'); |
1303
|
|
|
} |
1304
|
|
|
} |
1305
|
|
|
} |
1306
|
|
|
|
1307
|
|
|
/** |
1308
|
|
|
* Generic setter method for setting class properties. Will use the method set.ucfirst($prop) instead if that |
1309
|
|
|
* method exists at a child level (by default). Set $noChildMethods to true if you don't want to use |
1310
|
|
|
* any get.ucfirst($prop) method even if it exists, false otherwise (default). |
1311
|
|
|
* |
1312
|
|
|
* @param string $prop The name of the property to set. |
1313
|
|
|
* @param mixed $value The value of the property to set. |
1314
|
|
|
* @param bool $noChildMethods Set to true if you do not want to use setters in the child object, defaults to false. |
1315
|
|
|
* |
1316
|
|
|
* @since 1.0 |
1317
|
|
|
* |
1318
|
|
|
* @throws \Alpha\Exception\AlphaException |
1319
|
|
|
*/ |
1320
|
|
|
public function set($prop, $value, $noChildMethods = false) |
1321
|
|
|
{ |
1322
|
|
|
self::$logger->debug('>>set(prop=['.$prop.'], $value=['.print_r($value, true).'], noChildMethods=['.$noChildMethods.'])'); |
1323
|
|
|
|
1324
|
|
|
if (method_exists($this, 'before_set_callback')) { |
1325
|
|
|
$this->{'before_set_callback'}(); |
1326
|
|
|
} |
1327
|
|
|
|
1328
|
|
|
// handle attributes with a set.ucfirst($prop) method |
1329
|
|
|
if (!$noChildMethods && method_exists($this, 'set'.ucfirst($prop))) { |
1330
|
|
|
if (method_exists($this, 'after_set_callback')) { |
1331
|
|
|
$this->{'after_set_callback'}(); |
1332
|
|
|
} |
1333
|
|
|
|
1334
|
|
|
$methodName = 'set'.ucfirst($prop); |
1335
|
|
|
|
1336
|
|
|
$this->$methodName($value); |
1337
|
|
|
} else { |
1338
|
|
|
// handle attributes with no dedicated child set.ucfirst($prop) method |
1339
|
|
|
if (isset($this->$prop)) { |
1340
|
|
|
if (method_exists($this, 'after_set_callback')) { |
1341
|
|
|
$this->{'after_set_callback'}(); |
1342
|
|
|
} |
1343
|
|
|
|
1344
|
|
|
// complex types will have a setValue() method to call |
1345
|
|
|
if (is_object($this->$prop) && get_class($this->$prop) !== false) { |
1346
|
|
|
if (mb_strtoupper(get_class($this->$prop)) != 'DATE' && mb_strtoupper(get_class($this->$prop)) != 'TIMESTAMP') { |
1347
|
|
|
$this->$prop->setValue($value); |
1348
|
|
|
} else { |
1349
|
|
|
// Date and Timestamp objects have a special setter accepting a string |
1350
|
|
|
$this->$prop->populateFromString($value); |
1351
|
|
|
} |
1352
|
|
|
} else { |
1353
|
|
|
// simple types set directly |
1354
|
|
|
$this->$prop = $value; |
1355
|
|
|
} |
1356
|
|
|
} else { |
1357
|
|
|
throw new AlphaException('Could not set the property ['.$prop.'] on the object of the class ['.get_class($this).']. Property may not exist, or else does not have a setValue() method and is private or protected.'); |
1358
|
|
|
} |
1359
|
|
|
} |
1360
|
|
|
self::$logger->debug('<<set'); |
1361
|
|
|
} |
1362
|
|
|
|
1363
|
|
|
/** |
1364
|
|
|
* Gets the property object rather than the value for complex attributes. Returns false if |
1365
|
|
|
* the property exists but is private. |
1366
|
|
|
* |
1367
|
|
|
* @param string $prop The name of the property we are getting. |
1368
|
|
|
* |
1369
|
|
|
* @return \Alpha\Model\Type\Type|bool The complex type object found. |
1370
|
|
|
* |
1371
|
|
|
* @since 1.0 |
1372
|
|
|
* |
1373
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
1374
|
|
|
*/ |
1375
|
|
|
public function getPropObject($prop) |
1376
|
|
|
{ |
1377
|
|
|
self::$logger->debug('>>getPropObject(prop=['.$prop.'])'); |
1378
|
|
|
|
1379
|
|
|
if (method_exists($this, 'before_getPropObject_callback')) { |
1380
|
|
|
$this->{'before_getPropObject_callback'}(); |
1381
|
|
|
} |
1382
|
|
|
|
1383
|
|
|
// get the class attributes |
1384
|
|
|
$reflection = new \ReflectionObject($this); |
1385
|
|
|
$properties = $reflection->getProperties(); |
1386
|
|
|
|
1387
|
|
|
// firstly, check for private |
1388
|
|
|
$attribute = new ReflectionProperty($this, $prop); |
1389
|
|
|
|
1390
|
|
|
if ($attribute->isPrivate()) { |
1391
|
|
|
if (method_exists($this, 'after_getPropObject_callback')) { |
1392
|
|
|
$this->{'after_getPropObject_callback'}(); |
1393
|
|
|
} |
1394
|
|
|
|
1395
|
|
|
self::$logger->debug('<<getPropObject [false]'); |
1396
|
|
|
|
1397
|
|
|
return false; |
1398
|
|
|
} |
1399
|
|
|
|
1400
|
|
|
foreach ($properties as $propObj) { |
1401
|
|
|
$propName = $propObj->name; |
1402
|
|
|
|
1403
|
|
|
if ($prop == $propName) { |
1404
|
|
|
if (method_exists($this, 'after_getPropObject_callback')) { |
1405
|
|
|
$this->{'after_getPropObject_callback'}(); |
1406
|
|
|
} |
1407
|
|
|
|
1408
|
|
|
self::$logger->debug('<<getPropObject ['.var_export($this->$prop, true).']'); |
1409
|
|
|
|
1410
|
|
|
return $this->$prop; |
1411
|
|
|
} |
1412
|
|
|
} |
1413
|
|
|
|
1414
|
|
|
self::$logger->debug('<<getPropObject'); |
1415
|
|
|
throw new IllegalArguementException('Could not access the property object ['.$prop.'] on the object of class ['.get_class($this).']'); |
1416
|
|
|
} |
1417
|
|
|
|
1418
|
|
|
/** |
1419
|
|
|
* Checks to see if the table exists in the database for the current business class. |
1420
|
|
|
* |
1421
|
|
|
* @param bool $checkHistoryTable Set to true if you want to check for the existance of the _history table for this DAO. |
1422
|
|
|
* |
1423
|
|
|
* @return bool |
1424
|
|
|
* |
1425
|
|
|
* @since 1.0 |
1426
|
|
|
* |
1427
|
|
|
* @throws \Alpha\Exception\AlphaException |
1428
|
|
|
*/ |
1429
|
|
|
public function checkTableExists($checkHistoryTable = false) |
1430
|
|
|
{ |
1431
|
|
|
self::$logger->debug('>>checkTableExists()'); |
1432
|
|
|
|
1433
|
|
|
if (method_exists($this, 'before_checkTableExists_callback')) { |
1434
|
|
|
$this->{'before_checkTableExists_callback'}(); |
1435
|
|
|
} |
1436
|
|
|
|
1437
|
|
|
$config = ConfigProvider::getInstance(); |
1438
|
|
|
|
1439
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1440
|
|
|
$provider->setRecord($this); |
1441
|
|
|
$tableExists = $provider->checkTableExists($checkHistoryTable); |
1442
|
|
|
|
1443
|
|
|
if (method_exists($this, 'after_checkTableExists_callback')) { |
1444
|
|
|
$this->{'after_checkTableExists_callback'}(); |
1445
|
|
|
} |
1446
|
|
|
|
1447
|
|
|
self::$logger->debug('<<checkTableExists ['.$tableExists.']'); |
1448
|
|
|
|
1449
|
|
|
return $tableExists; |
1450
|
|
|
} |
1451
|
|
|
|
1452
|
|
|
/** |
1453
|
|
|
* Static method to check the database and see if the table for the indicated Record class name |
1454
|
|
|
* exists (assumes table name will be $recordClassName less "Object"). |
1455
|
|
|
* |
1456
|
|
|
* @param string $recordClassName The name of the business object class we are checking. |
1457
|
|
|
* @param bool $checkHistoryTable Set to true if you want to check for the existance of the _history table for this DAO. |
1458
|
|
|
* |
1459
|
|
|
* @return bool |
1460
|
|
|
* |
1461
|
|
|
* @since 1.0 |
1462
|
|
|
* |
1463
|
|
|
* @throws \Alpha\Exception\AlphaException |
1464
|
|
|
*/ |
1465
|
|
|
public static function checkRecordTableExists($recordClassName, $checkHistoryTable = false) |
1466
|
|
|
{ |
1467
|
|
|
if (self::$logger == null) { |
1468
|
|
|
self::$logger = new Logger('ActiveRecord'); |
1469
|
|
|
} |
1470
|
|
|
self::$logger->debug('>>checkRecordTableExists(RecordClassName=['.$recordClassName.'])'); |
1471
|
|
|
|
1472
|
|
|
$config = ConfigProvider::getInstance(); |
1473
|
|
|
|
1474
|
|
|
$provider = $config->get('db.provider.name'); |
1475
|
|
|
|
1476
|
|
|
$tableExists = $provider::checkRecordTableExists($recordClassName, $checkHistoryTable); |
1477
|
|
|
|
1478
|
|
|
self::$logger->debug('<<checkRecordTableExists ['.($tableExists ? 'true' : 'false').']'); |
1479
|
|
|
|
1480
|
|
|
return $tableExists; |
1481
|
|
|
} |
1482
|
|
|
|
1483
|
|
|
/** |
1484
|
|
|
* Checks to see if the table in the database matches (for fields) the business class definition, i.e. if the |
1485
|
|
|
* database table is in sync with the class definition. |
1486
|
|
|
* |
1487
|
|
|
* @return bool |
1488
|
|
|
* |
1489
|
|
|
* @since 1.0 |
1490
|
|
|
* |
1491
|
|
|
* @throws \Alpha\Exception\AlphaException |
1492
|
|
|
*/ |
1493
|
|
|
public function checkTableNeedsUpdate() |
1494
|
|
|
{ |
1495
|
|
|
self::$logger->debug('>>checkTableNeedsUpdate()'); |
1496
|
|
|
|
1497
|
|
|
$config = ConfigProvider::getInstance(); |
1498
|
|
|
|
1499
|
|
|
if (method_exists($this, 'before_checkTableNeedsUpdate_callback')) { |
1500
|
|
|
$this->{'before_checkTableNeedsUpdate_callback'}(); |
1501
|
|
|
} |
1502
|
|
|
|
1503
|
|
|
$tableExists = $this->checkTableExists(); |
1504
|
|
|
|
1505
|
|
|
if (!$tableExists) { |
1506
|
|
|
self::$logger->debug('<<checkTableNeedsUpdate [true]'); |
1507
|
|
|
|
1508
|
|
|
return true; |
1509
|
|
|
} else { |
1510
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1511
|
|
|
$provider->setRecord($this); |
1512
|
|
|
$updateRequired = $provider->checkTableNeedsUpdate(); |
1513
|
|
|
|
1514
|
|
|
if (method_exists($this, 'after_checkTableNeedsUpdate_callback')) { |
1515
|
|
|
$this->{'after_checkTableNeedsUpdate_callback'}(); |
1516
|
|
|
} |
1517
|
|
|
|
1518
|
|
|
self::$logger->debug('<<checkTableNeedsUpdate ['.$updateRequired.']'); |
1519
|
|
|
|
1520
|
|
|
return $updateRequired; |
1521
|
|
|
} |
1522
|
|
|
} |
1523
|
|
|
|
1524
|
|
|
/** |
1525
|
|
|
* Returns an array containing any properties on the class which have not been created on the database |
1526
|
|
|
* table yet. |
1527
|
|
|
* |
1528
|
|
|
* @return array An array of missing fields in the database table. |
1529
|
|
|
* |
1530
|
|
|
* @since 1.0 |
1531
|
|
|
* |
1532
|
|
|
* @throws \Alpha\Exception\AlphaException |
1533
|
|
|
*/ |
1534
|
|
|
public function findMissingFields() |
1535
|
|
|
{ |
1536
|
|
|
self::$logger->debug('>>findMissingFields()'); |
1537
|
|
|
|
1538
|
|
|
$config = ConfigProvider::getInstance(); |
1539
|
|
|
|
1540
|
|
|
if (method_exists($this, 'before_findMissingFields_callback')) { |
1541
|
|
|
$this->{'before_findMissingFields_callback'}(); |
1542
|
|
|
} |
1543
|
|
|
|
1544
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1545
|
|
|
$provider->setRecord($this); |
1546
|
|
|
$missingFields = $provider->findMissingFields(); |
1547
|
|
|
|
1548
|
|
|
if (method_exists($this, 'after_findMissingFields_callback')) { |
1549
|
|
|
$this->{'after_findMissingFields_callback'}(); |
1550
|
|
|
} |
1551
|
|
|
|
1552
|
|
|
self::$logger->debug('<<findMissingFields ['.var_export($missingFields, true).']'); |
1553
|
|
|
|
1554
|
|
|
return $missingFields; |
1555
|
|
|
} |
1556
|
|
|
|
1557
|
|
|
/** |
1558
|
|
|
* Getter for the TABLE_NAME, which should be set by a child of this class. |
1559
|
|
|
* |
1560
|
|
|
* @return string The table name in the database. |
1561
|
|
|
* |
1562
|
|
|
* @since 1.0 |
1563
|
|
|
* |
1564
|
|
|
* @throws \Alpha\Exception\AlphaException |
1565
|
|
|
*/ |
1566
|
|
|
public function getTableName() |
1567
|
|
|
{ |
1568
|
|
|
self::$logger->debug('>>getTableName()'); |
1569
|
|
|
|
1570
|
|
|
$className = get_class($this); |
1571
|
|
|
|
1572
|
|
|
$tableName = $className::TABLE_NAME; |
1573
|
|
|
|
1574
|
|
|
if (!empty($tableName)) { |
1575
|
|
|
self::$logger->debug('<<getTableName ['.$tableName.']'); |
1576
|
|
|
|
1577
|
|
|
return $tableName; |
1578
|
|
|
} else { |
1579
|
|
|
throw new AlphaException('Error: no TABLE_NAME constant set for the class '.get_class($this)); |
1580
|
|
|
} |
1581
|
|
|
} |
1582
|
|
|
|
1583
|
|
|
/** |
1584
|
|
|
* Method for getting the ID of the person who created this record. |
1585
|
|
|
* |
1586
|
|
|
* @return \Alpha\Model\Type\Integer The ID of the creator. |
1587
|
|
|
* |
1588
|
|
|
* @since 1.0 |
1589
|
|
|
*/ |
1590
|
|
|
public function getCreatorId() |
1591
|
|
|
{ |
1592
|
|
|
self::$logger->debug('>>getCreatorId()'); |
1593
|
|
|
self::$logger->debug('<<getCreatorId ['.$this->created_by.']'); |
1594
|
|
|
|
1595
|
|
|
return $this->created_by; |
1596
|
|
|
} |
1597
|
|
|
|
1598
|
|
|
/** |
1599
|
|
|
* Method for getting the ID of the person who updated this record. |
1600
|
|
|
* |
1601
|
|
|
* @return \Alpha\Model\Type\Integer The ID of the updator. |
1602
|
|
|
* |
1603
|
|
|
* @since 1.0 |
1604
|
|
|
*/ |
1605
|
|
|
public function getUpdatorId() |
1606
|
|
|
{ |
1607
|
|
|
self::$logger->debug('>>getUpdatorId()'); |
1608
|
|
|
self::$logger->debug('<<getUpdatorId ['.$this->updated_by.']'); |
1609
|
|
|
|
1610
|
|
|
return $this->updated_by; |
1611
|
|
|
} |
1612
|
|
|
|
1613
|
|
|
/** |
1614
|
|
|
* Method for getting the date/time of when the Record was created. |
1615
|
|
|
* |
1616
|
|
|
* @return \Alpha\Model\Type\Timestamp |
1617
|
|
|
* |
1618
|
|
|
* @since 1.0 |
1619
|
|
|
*/ |
1620
|
|
|
public function getCreateTS() |
1621
|
|
|
{ |
1622
|
|
|
self::$logger->debug('>>getCreateTS()'); |
1623
|
|
|
self::$logger->debug('<<getCreateTS ['.$this->created_ts.']'); |
1624
|
|
|
|
1625
|
|
|
return $this->created_ts; |
1626
|
|
|
} |
1627
|
|
|
|
1628
|
|
|
/** |
1629
|
|
|
* Method for getting the date/time of when the Record was last updated. |
1630
|
|
|
* |
1631
|
|
|
* @return \Alpha\Model\Type\Timestamp |
1632
|
|
|
* |
1633
|
|
|
* @since 1.0 |
1634
|
|
|
*/ |
1635
|
|
|
public function getUpdateTS() |
1636
|
|
|
{ |
1637
|
|
|
self::$logger->debug('>>getUpdateTS()'); |
1638
|
|
|
self::$logger->debug('<<getUpdateTS ['.$this->updated_ts.']'); |
1639
|
|
|
|
1640
|
|
|
return $this->updated_ts; |
1641
|
|
|
} |
1642
|
|
|
|
1643
|
|
|
/** |
1644
|
|
|
* Adds the name of the attribute provided to the list of transient (non-saved) attributes for this record. |
1645
|
|
|
* |
1646
|
|
|
* @param string $attributeName The name of the attribute to not save. |
1647
|
|
|
* |
1648
|
|
|
* @since 1.0 |
1649
|
|
|
*/ |
1650
|
|
|
public function markTransient($attributeName) |
1651
|
|
|
{ |
1652
|
|
|
self::$logger->debug('>>markTransient(attributeName=['.$attributeName.'])'); |
1653
|
|
|
self::$logger->debug('<<markTransient'); |
1654
|
|
|
array_push($this->transientAttributes, $attributeName); |
1655
|
|
|
} |
1656
|
|
|
|
1657
|
|
|
/** |
1658
|
|
|
* Removes the name of the attribute provided from the list of transient (non-saved) attributes for this record, |
1659
|
|
|
* ensuring that it will be saved on the next attempt. |
1660
|
|
|
* |
1661
|
|
|
* @param string $attributeName The name of the attribute to save. |
1662
|
|
|
* |
1663
|
|
|
* @since 1.0 |
1664
|
|
|
*/ |
1665
|
|
|
public function markPersistent($attributeName) |
1666
|
|
|
{ |
1667
|
|
|
self::$logger->debug('>>markPersistent(attributeName=['.$attributeName.'])'); |
1668
|
|
|
self::$logger->debug('<<markPersistent'); |
1669
|
|
|
$this->transientAttributes = array_diff($this->transientAttributes, array($attributeName)); |
1670
|
|
|
} |
1671
|
|
|
|
1672
|
|
|
/** |
1673
|
|
|
* Adds the name of the attribute(s) provided to the list of unique (constrained) attributes for this record. |
1674
|
|
|
* |
1675
|
|
|
* @param string $attribute1Name The first attribute to mark unique in the database. |
1676
|
|
|
* @param string $attribute2Name The second attribute to mark unique in the databse (optional, use only for composite keys). |
1677
|
|
|
* @param string $attribute3Name The third attribute to mark unique in the databse (optional, use only for composite keys). |
1678
|
|
|
* |
1679
|
|
|
* @since 1.0 |
1680
|
|
|
*/ |
1681
|
|
|
protected function markUnique($attribute1Name, $attribute2Name = '', $attribute3Name = '') |
1682
|
|
|
{ |
1683
|
|
|
self::$logger->debug('>>markUnique(attribute1Name=['.$attribute1Name.'], attribute2Name=['.$attribute2Name.'], attribute3Name=['.$attribute3Name.'])'); |
1684
|
|
|
|
1685
|
|
|
if (empty($attribute2Name)) { |
1686
|
|
|
array_push($this->uniqueAttributes, $attribute1Name); |
1687
|
|
|
} else { |
1688
|
|
|
// Process composite unique keys: add them seperated by a + sign |
1689
|
|
|
if ($attribute3Name == '') { |
1690
|
|
|
$attributes = $attribute1Name.'+'.$attribute2Name; |
1691
|
|
|
} else { |
1692
|
|
|
$attributes = $attribute1Name.'+'.$attribute2Name.'+'.$attribute3Name; |
1693
|
|
|
} |
1694
|
|
|
|
1695
|
|
|
array_push($this->uniqueAttributes, $attributes); |
1696
|
|
|
} |
1697
|
|
|
|
1698
|
|
|
self::$logger->debug('<<markUnique'); |
1699
|
|
|
} |
1700
|
|
|
|
1701
|
|
|
/** |
1702
|
|
|
* Returns the array of names of unique attributes on this record. |
1703
|
|
|
* |
1704
|
|
|
* @return array |
1705
|
|
|
* |
1706
|
|
|
* @since 1.1 |
1707
|
|
|
*/ |
1708
|
|
|
public function getUniqueAttributes() |
1709
|
|
|
{ |
1710
|
|
|
self::$logger->debug('>>getUniqueAttributes()'); |
1711
|
|
|
self::$logger->debug('<<getUniqueAttributes: ['.print_r($this->uniqueAttributes, true).']'); |
1712
|
|
|
|
1713
|
|
|
return $this->uniqueAttributes; |
1714
|
|
|
} |
1715
|
|
|
|
1716
|
|
|
/** |
1717
|
|
|
* Gets an array of all of the names of the active database indexes for this class. |
1718
|
|
|
* |
1719
|
|
|
* @return array An array of database indexes on this table. |
1720
|
|
|
* |
1721
|
|
|
* @since 1.0 |
1722
|
|
|
* |
1723
|
|
|
* @throws \Alpha\Exception\AlphaException |
1724
|
|
|
*/ |
1725
|
|
|
public function getIndexes() |
1726
|
|
|
{ |
1727
|
|
|
self::$logger->debug('>>getIndexes()'); |
1728
|
|
|
|
1729
|
|
|
$config = ConfigProvider::getInstance(); |
1730
|
|
|
|
1731
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1732
|
|
|
$provider->setRecord($this); |
1733
|
|
|
$indexNames = $provider->getIndexes(); |
1734
|
|
|
|
1735
|
|
|
self::$logger->debug('<<getIndexes ['.print_r($indexNames, true).']'); |
1736
|
|
|
|
1737
|
|
|
return $indexNames; |
1738
|
|
|
} |
1739
|
|
|
|
1740
|
|
|
/** |
1741
|
|
|
* Creates a foreign key constraint (index) in the database on the given attribute. |
1742
|
|
|
* |
1743
|
|
|
* @param string $attributeName The name of the attribute to apply the index on. |
1744
|
|
|
* @param string $relatedClass The name of the related class in the format "NameObject". |
1745
|
|
|
* @param string $relatedClassAttribute The name of the field to relate to on the related class. |
1746
|
|
|
* @param string $indexName The optional name for the index, will calculate if not provided. |
1747
|
|
|
* |
1748
|
|
|
* @since 1.0 |
1749
|
|
|
* |
1750
|
|
|
* @throws \Alpha\Exception\FailedIndexCreateException |
1751
|
|
|
*/ |
1752
|
|
|
public function createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute, $indexName = null) |
1753
|
|
|
{ |
1754
|
|
|
self::$logger->debug('>>createForeignIndex(attributeName=['.$attributeName.'], relatedClass=['.$relatedClass.'], relatedClassAttribute=['.$relatedClassAttribute.'], indexName=['.$indexName.']'); |
1755
|
|
|
|
1756
|
|
|
$config = ConfigProvider::getInstance(); |
1757
|
|
|
|
1758
|
|
|
if (method_exists($this, 'before_createForeignIndex_callback')) { |
1759
|
|
|
$this->{'before_createForeignIndex_callback'}(); |
1760
|
|
|
} |
1761
|
|
|
|
1762
|
|
|
$relatedRecord = new $relatedClass(); |
1763
|
|
|
$tableName = $relatedRecord->getTableName(); |
1764
|
|
|
|
1765
|
|
|
// if the relation is on itself (table-wise), exit without attempting to create the foreign keys |
1766
|
|
|
if ($this->getTableName() == $tableName) { |
1767
|
|
|
self::$logger->debug('<<createForeignIndex'); |
1768
|
|
|
|
1769
|
|
|
return; |
1770
|
|
|
} |
1771
|
|
|
|
1772
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1773
|
|
|
$provider->setRecord($this); |
1774
|
|
|
$provider->createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute, $indexName); |
1775
|
|
|
|
1776
|
|
|
if (method_exists($this, 'after_createForeignIndex_callback')) { |
1777
|
|
|
$this->{'after_createForeignIndex_callback'}(); |
1778
|
|
|
} |
1779
|
|
|
|
1780
|
|
|
self::$logger->debug('<<createForeignIndex'); |
1781
|
|
|
} |
1782
|
|
|
|
1783
|
|
|
/** |
1784
|
|
|
* Creates a unique index in the database on the given attribute(s). |
1785
|
|
|
* |
1786
|
|
|
* @param string $attribute1Name The first attribute to mark unique in the database. |
1787
|
|
|
* @param string $attribute2Name The second attribute to mark unique in the databse (optional, use only for composite keys). |
1788
|
|
|
* @param string $attribute3Name The third attribute to mark unique in the databse (optional, use only for composite keys). |
1789
|
|
|
* |
1790
|
|
|
* @since 1.0 |
1791
|
|
|
* |
1792
|
|
|
* @throws \Alpha\Exception\FailedIndexCreateException |
1793
|
|
|
*/ |
1794
|
|
|
public function createUniqueIndex($attribute1Name, $attribute2Name = '', $attribute3Name = '') |
1795
|
|
|
{ |
1796
|
|
|
self::$logger->debug('>>createUniqueIndex(attribute1Name=['.$attribute1Name.'], attribute2Name=['.$attribute2Name.'], attribute3Name=['.$attribute3Name.'])'); |
1797
|
|
|
|
1798
|
|
|
if (method_exists($this, 'before_createUniqueIndex_callback')) { |
1799
|
|
|
$this->{'before_createUniqueIndex_callback'}(); |
1800
|
|
|
} |
1801
|
|
|
|
1802
|
|
|
$config = ConfigProvider::getInstance(); |
1803
|
|
|
|
1804
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
1805
|
|
|
$provider->setRecord($this); |
1806
|
|
|
$provider->createUniqueIndex($attribute1Name, $attribute2Name, $attribute3Name); |
1807
|
|
|
|
1808
|
|
|
if (method_exists($this, 'after_createUniqueIndex_callback')) { |
1809
|
|
|
$this->{'before_createUniqueIndex_callback'}(); |
1810
|
|
|
} |
1811
|
|
|
|
1812
|
|
|
self::$logger->debug('<<createUniqueIndex'); |
1813
|
|
|
} |
1814
|
|
|
|
1815
|
|
|
/** |
1816
|
|
|
* Gets the data labels array. |
1817
|
|
|
* |
1818
|
|
|
* @return array An array of attribute labels. |
1819
|
|
|
* |
1820
|
|
|
* @since 1.0 |
1821
|
|
|
*/ |
1822
|
|
|
public function getDataLabels() |
1823
|
|
|
{ |
1824
|
|
|
self::$logger->debug('>>getDataLabels()'); |
1825
|
|
|
self::$logger->debug('<<getDataLabels() ['.var_export($this->dataLabels, true).'])'); |
1826
|
|
|
|
1827
|
|
|
return $this->dataLabels; |
1828
|
|
|
} |
1829
|
|
|
|
1830
|
|
|
/** |
1831
|
|
|
* Sets the data labels array. |
1832
|
|
|
* |
1833
|
|
|
* @param array $labels |
1834
|
|
|
* |
1835
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
1836
|
|
|
* |
1837
|
|
|
* @since 1.2 |
1838
|
|
|
*/ |
1839
|
|
|
public function setDataLabels($labels) |
1840
|
|
|
{ |
1841
|
|
|
self::$logger->debug('>>setDataLabels(labels=['.print_r($labels, true).'])'); |
1842
|
|
|
|
1843
|
|
|
if (is_array($labels)) { |
1844
|
|
|
$this->dataLabels = $labels; |
1845
|
|
|
} else { |
1846
|
|
|
throw new IllegalArguementException('The value ['.print_r($labels, true).'] provided to setDataLabels() is not a valid array!'); |
1847
|
|
|
} |
1848
|
|
|
|
1849
|
|
|
self::$logger->debug('<<setDataLabels()'); |
1850
|
|
|
} |
1851
|
|
|
|
1852
|
|
|
/** |
1853
|
|
|
* Gets the data label for the given attribute name. |
1854
|
|
|
* |
1855
|
|
|
* @param $att The attribute name to get the label for. |
1856
|
|
|
* |
1857
|
|
|
* @return string |
1858
|
|
|
* |
1859
|
|
|
* @since 1.0 |
1860
|
|
|
* |
1861
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
1862
|
|
|
*/ |
1863
|
|
|
public function getDataLabel($att) |
1864
|
|
|
{ |
1865
|
|
|
self::$logger->debug('>>getDataLabel(att=['.$att.'])'); |
1866
|
|
|
|
1867
|
|
|
if (in_array($att, array_keys($this->dataLabels))) { |
1868
|
|
|
self::$logger->debug('<<getDataLabel ['.$this->dataLabels[$att].'])'); |
1869
|
|
|
|
1870
|
|
|
return $this->dataLabels[$att]; |
1871
|
|
|
} else { |
1872
|
|
|
self::$logger->debug('<<getDataLabel'); |
1873
|
|
|
throw new IllegalArguementException('No data label found on the class ['.get_class($this).'] for the attribute ['.$att.']'); |
1874
|
|
|
} |
1875
|
|
|
} |
1876
|
|
|
|
1877
|
|
|
/** |
1878
|
|
|
* Loops over the core and custom Record directories and builds an array of all of the Record class names in the system. |
1879
|
|
|
* |
1880
|
|
|
* @return array An array of business object class names. |
1881
|
|
|
* |
1882
|
|
|
* @since 1.0 |
1883
|
|
|
*/ |
1884
|
|
|
public static function getRecordClassNames() |
1885
|
|
|
{ |
1886
|
|
|
if (self::$logger == null) { |
1887
|
|
|
self::$logger = new Logger('ActiveRecord'); |
1888
|
|
|
} |
1889
|
|
|
self::$logger->debug('>>getRecordClassNames()'); |
1890
|
|
|
|
1891
|
|
|
$config = ConfigProvider::getInstance(); |
1892
|
|
|
|
1893
|
|
|
$classNameArray = array(); |
1894
|
|
|
|
1895
|
|
|
if (file_exists($config->get('app.root').'src/Model')) { // it is possible it has not been created yet... |
1896
|
|
|
// first get any custom records |
1897
|
|
|
$handle = opendir($config->get('app.root').'src/Model'); |
1898
|
|
|
|
1899
|
|
|
// loop over the business object directory |
1900
|
|
|
while (false !== ($file = readdir($handle))) { |
1901
|
|
|
if (preg_match('/.php/', $file)) { |
1902
|
|
|
$classname = 'Model\\'.mb_substr($file, 0, -4); |
1903
|
|
|
|
1904
|
|
|
if (class_exists($classname)) { |
1905
|
|
|
array_push($classNameArray, $classname); |
1906
|
|
|
} |
1907
|
|
|
} |
1908
|
|
|
} |
1909
|
|
|
} |
1910
|
|
|
|
1911
|
|
|
// now loop over the core records provided with Alpha |
1912
|
|
|
if (file_exists($config->get('app.root').'Alpha/Model')) { |
1913
|
|
|
$handle = opendir($config->get('app.root').'Alpha/Model'); |
1914
|
|
|
} else { |
1915
|
|
|
$handle = opendir($config->get('app.root').'vendor/alphadevx/alpha/Alpha/Model'); |
1916
|
|
|
} |
1917
|
|
|
|
1918
|
|
|
// loop over the business object directory |
1919
|
|
|
while (false !== ($file = readdir($handle))) { |
1920
|
|
|
if (preg_match('/.php/', $file)) { |
1921
|
|
|
$classname = 'Alpha\\Model\\'.mb_substr($file, 0, -4); |
1922
|
|
|
|
1923
|
|
|
if (class_exists($classname) && substr($classname, 0, 24) != 'Alpha\\Model\\ActiveRecord') { |
1924
|
|
|
array_push($classNameArray, $classname); |
1925
|
|
|
} |
1926
|
|
|
} |
1927
|
|
|
} |
1928
|
|
|
|
1929
|
|
|
asort($classNameArray); |
1930
|
|
|
self::$logger->debug('<<getRecordClassNames ['.var_export($classNameArray, true).']'); |
1931
|
|
|
|
1932
|
|
|
return $classNameArray; |
1933
|
|
|
} |
1934
|
|
|
|
1935
|
|
|
/** |
1936
|
|
|
* Get the array of default attribute names. |
1937
|
|
|
* |
1938
|
|
|
* @return array An array of attribute names. |
1939
|
|
|
* |
1940
|
|
|
* @since 1.0 |
1941
|
|
|
*/ |
1942
|
|
|
public function getDefaultAttributes() |
1943
|
|
|
{ |
1944
|
|
|
self::$logger->debug('>>getDefaultAttributes()'); |
1945
|
|
|
self::$logger->debug('<<getDefaultAttributes ['.var_export($this->defaultAttributes, true).']'); |
1946
|
|
|
|
1947
|
|
|
return $this->defaultAttributes; |
1948
|
|
|
} |
1949
|
|
|
|
1950
|
|
|
/** |
1951
|
|
|
* Get the array of transient attribute names. |
1952
|
|
|
* |
1953
|
|
|
* @return array An array of attribute names. |
1954
|
|
|
* |
1955
|
|
|
* @since 1.0 |
1956
|
|
|
*/ |
1957
|
|
|
public function getTransientAttributes() |
1958
|
|
|
{ |
1959
|
|
|
self::$logger->debug('>>getTransientAttributes()'); |
1960
|
|
|
self::$logger->debug('<<getTransientAttributes ['.var_export($this->transientAttributes, true).']'); |
1961
|
|
|
|
1962
|
|
|
return $this->transientAttributes; |
1963
|
|
|
} |
1964
|
|
|
|
1965
|
|
|
/** |
1966
|
|
|
* Get the array of persistent attribute names, i.e. those that are saved in the database. |
1967
|
|
|
* |
1968
|
|
|
* @return array An array of attribute names. |
1969
|
|
|
* |
1970
|
|
|
* @since 1.0 |
1971
|
|
|
*/ |
1972
|
|
|
public function getPersistentAttributes() |
1973
|
|
|
{ |
1974
|
|
|
self::$logger->debug('>>getPersistentAttributes()'); |
1975
|
|
|
|
1976
|
|
|
$attributes = array(); |
1977
|
|
|
|
1978
|
|
|
// get the class attributes |
1979
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
1980
|
|
|
$properties = $reflection->getProperties(); |
1981
|
|
|
|
1982
|
|
|
foreach ($properties as $propObj) { |
1983
|
|
|
$propName = $propObj->name; |
1984
|
|
|
|
1985
|
|
|
// filter transient attributes |
1986
|
|
|
if (!in_array($propName, $this->transientAttributes)) { |
1987
|
|
|
array_push($attributes, $propName); |
1988
|
|
|
} |
1989
|
|
|
} |
1990
|
|
|
|
1991
|
|
|
self::$logger->debug('<<getPersistentAttributes ['.var_export($attributes, true).']'); |
1992
|
|
|
|
1993
|
|
|
return $attributes; |
1994
|
|
|
} |
1995
|
|
|
|
1996
|
|
|
/** |
1997
|
|
|
* Setter for the Object ID (ID). |
1998
|
|
|
* |
1999
|
|
|
* @param int $ID The Object ID. |
2000
|
|
|
* |
2001
|
|
|
* @since 1.0 |
2002
|
|
|
*/ |
2003
|
|
|
public function setID($ID) |
2004
|
|
|
{ |
2005
|
|
|
self::$logger->debug('>>setID(ID=['.$ID.'])'); |
2006
|
|
|
self::$logger->debug('<<setID'); |
2007
|
|
|
$this->ID = $ID; |
2008
|
|
|
} |
2009
|
|
|
|
2010
|
|
|
/** |
2011
|
|
|
* Inspector to see if the business object is transient (not presently stored in the database). |
2012
|
|
|
* |
2013
|
|
|
* @return bool |
2014
|
|
|
* |
2015
|
|
|
* @since 1.0 |
2016
|
|
|
*/ |
2017
|
|
|
public function isTransient() |
2018
|
|
|
{ |
2019
|
|
|
self::$logger->debug('>>isTransient()'); |
2020
|
|
|
|
2021
|
|
|
if (empty($this->ID) || !isset($this->ID) || $this->ID == '00000000000') { |
2022
|
|
|
self::$logger->debug('<<isTransient [true]'); |
2023
|
|
|
|
2024
|
|
|
return true; |
2025
|
|
|
} else { |
2026
|
|
|
self::$logger->debug('<<isTransient [false]'); |
2027
|
|
|
|
2028
|
|
|
return false; |
2029
|
|
|
} |
2030
|
|
|
} |
2031
|
|
|
|
2032
|
|
|
/** |
2033
|
|
|
* Get the last database query run on this object. |
2034
|
|
|
* |
2035
|
|
|
* @return string An SQL query string. |
2036
|
|
|
* |
2037
|
|
|
* @since 1.0 |
2038
|
|
|
*/ |
2039
|
|
|
public function getLastQuery() |
2040
|
|
|
{ |
2041
|
|
|
self::$logger->debug('>>getLastQuery()'); |
2042
|
|
|
self::$logger->debug('<<getLastQuery ['.$this->lastQuery.']'); |
2043
|
|
|
|
2044
|
|
|
return $this->lastQuery; |
2045
|
|
|
} |
2046
|
|
|
|
2047
|
|
|
/** |
2048
|
|
|
* Unsets all of the attributes of this object to null. |
2049
|
|
|
* |
2050
|
|
|
* @since 1.0 |
2051
|
|
|
*/ |
2052
|
|
|
private function clear() |
2053
|
|
|
{ |
2054
|
|
|
self::$logger->debug('>>clear()'); |
2055
|
|
|
|
2056
|
|
|
// get the class attributes |
2057
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
2058
|
|
|
$properties = $reflection->getProperties(); |
2059
|
|
|
|
2060
|
|
|
foreach ($properties as $propObj) { |
2061
|
|
|
$propName = $propObj->name; |
2062
|
|
|
if (!$propObj->isPrivate()) { |
2063
|
|
|
unset($this->$propName); |
2064
|
|
|
} |
2065
|
|
|
} |
2066
|
|
|
|
2067
|
|
|
self::$logger->debug('<<clear'); |
2068
|
|
|
} |
2069
|
|
|
|
2070
|
|
|
/** |
2071
|
|
|
* Reloads the object from the database, overwritting any attribute values in memory. |
2072
|
|
|
* |
2073
|
|
|
* @since 1.0 |
2074
|
|
|
* |
2075
|
|
|
* @throws \Alpha\Exception\AlphaException |
2076
|
|
|
*/ |
2077
|
|
|
public function reload() |
2078
|
|
|
{ |
2079
|
|
|
self::$logger->debug('>>reload()'); |
2080
|
|
|
|
2081
|
|
|
if (!$this->isTransient()) { |
2082
|
|
|
$this->load($this->getID()); |
2083
|
|
|
} else { |
2084
|
|
|
throw new AlphaException('Cannot reload transient object from database!'); |
2085
|
|
|
} |
2086
|
|
|
self::$logger->debug('<<reload'); |
2087
|
|
|
} |
2088
|
|
|
|
2089
|
|
|
/** |
2090
|
|
|
* Loads the definition from the file system for the Record class name provided. |
2091
|
|
|
* |
2092
|
|
|
* @param string $classname The name of the business object class name. |
2093
|
|
|
* |
2094
|
|
|
* @since 1.0 |
2095
|
|
|
* |
2096
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
2097
|
|
|
* |
2098
|
|
|
* @deprecated Use autoloader! |
2099
|
|
|
*/ |
2100
|
|
|
public static function loadClassDef($classname) |
2101
|
|
|
{ |
2102
|
|
|
if (self::$logger == null) { |
2103
|
|
|
self::$logger = new Logger('ActiveRecord'); |
2104
|
|
|
} |
2105
|
|
|
self::$logger->debug('>>loadClassDef(classname=['.$classname.'])'); |
2106
|
|
|
|
2107
|
|
|
$config = ConfigProvider::getInstance(); |
2108
|
|
|
|
2109
|
|
|
if (file_exists($config->get('app.root').'Model/'.$classname.'.php')) { |
2110
|
|
|
require_once $config->get('app.root').'Model/'.$classname.'.php'; |
2111
|
|
|
} elseif (file_exists($config->get('app.root').'alpha/Alpha/Model/'.$classname.'.php')) { |
2112
|
|
|
require_once $config->get('app.root').'alpha/Alpha/Model/'.$classname.'.php'; |
2113
|
|
|
} elseif (file_exists($config->get('app.root').'alpha/Alpha/Model/Types/'.$classname.'.php')) { |
2114
|
|
|
require_once $config->get('app.root').'alpha/Alpha/Model/Types/'.$classname.'.php'; |
2115
|
|
|
} else { |
2116
|
|
|
throw new IllegalArguementException('The class ['.$classname.'] is not defined anywhere!'); |
2117
|
|
|
} |
2118
|
|
|
|
2119
|
|
|
self::$logger->debug('<<loadClassDef'); |
2120
|
|
|
} |
2121
|
|
|
|
2122
|
|
|
/** |
2123
|
|
|
* Checks that a record exists for the Record in the database. |
2124
|
|
|
* |
2125
|
|
|
* @param int $ID The Object ID of the object we want to see whether it exists or not. |
2126
|
|
|
* |
2127
|
|
|
* @return bool |
2128
|
|
|
* |
2129
|
|
|
* @since 1.0 |
2130
|
|
|
* |
2131
|
|
|
* @throws \Alpha\Exception\AlphaException |
2132
|
|
|
*/ |
2133
|
|
|
public function checkRecordExists($ID) |
2134
|
|
|
{ |
2135
|
|
|
self::$logger->debug('>>checkRecordExists(ID=['.$ID.'])'); |
2136
|
|
|
|
2137
|
|
|
if (method_exists($this, 'before_checkRecordExists_callback')) { |
2138
|
|
|
$this->{'before_checkRecordExists_callback'}(); |
2139
|
|
|
} |
2140
|
|
|
|
2141
|
|
|
$config = ConfigProvider::getInstance(); |
2142
|
|
|
|
2143
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2144
|
|
|
$provider->setRecord($this); |
2145
|
|
|
$recordExists = $provider->checkRecordExists($ID); |
2146
|
|
|
|
2147
|
|
|
if (method_exists($this, 'after_checkRecordExists_callback')) { |
2148
|
|
|
$this->{'after_checkRecordExists_callback'}(); |
2149
|
|
|
} |
2150
|
|
|
|
2151
|
|
|
self::$logger->debug('<<checkRecordExists ['.$recordExists.']'); |
2152
|
|
|
|
2153
|
|
|
return $recordExists; |
2154
|
|
|
} |
2155
|
|
|
|
2156
|
|
|
/** |
2157
|
|
|
* Checks to see if the table name matches the classname, and if not if the table |
2158
|
|
|
* name matches the classname name of another record, i.e. the table is used to store |
2159
|
|
|
* multiple types of records. |
2160
|
|
|
* |
2161
|
|
|
* @return bool |
2162
|
|
|
* |
2163
|
|
|
* @since 1.0 |
2164
|
|
|
* |
2165
|
|
|
* @throws \Alpha\Exception\BadTableNameException |
2166
|
|
|
*/ |
2167
|
|
|
public function isTableOverloaded() |
2168
|
|
|
{ |
2169
|
|
|
self::$logger->debug('>>isTableOverloaded()'); |
2170
|
|
|
|
2171
|
|
|
$config = ConfigProvider::getInstance(); |
2172
|
|
|
|
2173
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2174
|
|
|
$provider->setRecord($this); |
2175
|
|
|
$isOverloaded = $provider->isTableOverloaded(); |
2176
|
|
|
|
2177
|
|
|
self::$logger->debug('<<isTableOverloaded ['.$isOverloaded.']'); |
2178
|
|
|
|
2179
|
|
|
return $isOverloaded; |
2180
|
|
|
} |
2181
|
|
|
|
2182
|
|
|
/** |
2183
|
|
|
* Starts a new database transaction. |
2184
|
|
|
* |
2185
|
|
|
* @param ActiveRecord $record The ActiveRecord instance to pass to the database provider. Leave empty to have a new Person passed. |
2186
|
|
|
* |
2187
|
|
|
* @since 1.0 |
2188
|
|
|
* |
2189
|
|
|
* @throws \Alpha\Exception\AlphaException |
2190
|
|
|
*/ |
2191
|
|
|
public static function begin($record = null) |
2192
|
|
|
{ |
2193
|
|
|
if (self::$logger == null) { |
2194
|
|
|
self::$logger = new Logger('ActiveRecord'); |
2195
|
|
|
} |
2196
|
|
|
self::$logger->debug('>>begin()'); |
2197
|
|
|
|
2198
|
|
|
$config = ConfigProvider::getInstance(); |
2199
|
|
|
|
2200
|
|
|
if (isset($record)) { |
2201
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2202
|
|
|
$provider->setRecord($record); |
2203
|
|
|
} else { |
2204
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2205
|
|
|
$provider->setRecord(new Person()); |
2206
|
|
|
} |
2207
|
|
|
|
2208
|
|
|
try { |
2209
|
|
|
$provider->begin(); |
2210
|
|
|
} catch (\Exception $e) { |
2211
|
|
|
throw new AlphaException('Error beginning a new transaction, error is ['.$e->getMessage().']'); |
2212
|
|
|
} |
2213
|
|
|
|
2214
|
|
|
self::$logger->debug('<<begin'); |
2215
|
|
|
} |
2216
|
|
|
|
2217
|
|
|
/** |
2218
|
|
|
* Commits the current database transaction. |
2219
|
|
|
* |
2220
|
|
|
* @param ActiveRecord $record The ActiveRecord instance to pass to the database provider. Leave empty to have a new Person passed. |
2221
|
|
|
* |
2222
|
|
|
* @since 1.0 |
2223
|
|
|
* |
2224
|
|
|
* @throws \Alpha\Exception\FailedSaveException |
2225
|
|
|
*/ |
2226
|
|
|
public static function commit($record = null) |
2227
|
|
|
{ |
2228
|
|
|
if (self::$logger == null) { |
2229
|
|
|
self::$logger = new Logger('ActiveRecord'); |
2230
|
|
|
} |
2231
|
|
|
self::$logger->debug('>>commit()'); |
2232
|
|
|
|
2233
|
|
|
$config = ConfigProvider::getInstance(); |
2234
|
|
|
|
2235
|
|
|
if (isset($record)) { |
2236
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2237
|
|
|
$provider->setRecord($record); |
2238
|
|
|
} else { |
2239
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2240
|
|
|
$provider->setRecord(new Person()); |
2241
|
|
|
} |
2242
|
|
|
|
2243
|
|
|
try { |
2244
|
|
|
$provider->commit(); |
2245
|
|
|
} catch (\Exception $e) { |
2246
|
|
|
throw new FailedSaveException('Error commiting a transaction, error is ['.$e->getMessage().']'); |
2247
|
|
|
} |
2248
|
|
|
|
2249
|
|
|
self::$logger->debug('<<commit'); |
2250
|
|
|
} |
2251
|
|
|
|
2252
|
|
|
/** |
2253
|
|
|
* Aborts the current database transaction. |
2254
|
|
|
* |
2255
|
|
|
* @param ActiveRecord $record The ActiveRecord instance to pass to the database provider. Leave empty to have a new Person passed. |
2256
|
|
|
* |
2257
|
|
|
* @since 1.0 |
2258
|
|
|
* |
2259
|
|
|
* @throws \Alpha\Exception\AlphaException |
2260
|
|
|
*/ |
2261
|
|
|
public static function rollback($record = null) |
2262
|
|
|
{ |
2263
|
|
|
if (self::$logger == null) { |
2264
|
|
|
self::$logger = new Logger('ActiveRecord'); |
2265
|
|
|
} |
2266
|
|
|
self::$logger->debug('>>rollback()'); |
2267
|
|
|
|
2268
|
|
|
$config = ConfigProvider::getInstance(); |
2269
|
|
|
|
2270
|
|
|
if (isset($record)) { |
2271
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2272
|
|
|
$provider->setRecord($record); |
2273
|
|
|
} else { |
2274
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2275
|
|
|
$provider->setRecord(new Person()); |
2276
|
|
|
} |
2277
|
|
|
|
2278
|
|
|
try { |
2279
|
|
|
$provider->rollback(); |
2280
|
|
|
} catch (\Exception $e) { |
2281
|
|
|
throw new FailedSaveException('Error aborting a transaction, error is ['.$e->getMessage().']'); |
2282
|
|
|
} |
2283
|
|
|
|
2284
|
|
|
self::$logger->debug('<<rollback'); |
2285
|
|
|
} |
2286
|
|
|
|
2287
|
|
|
/** |
2288
|
|
|
* Static method that tries to determine if the system database has been installed or not. |
2289
|
|
|
* |
2290
|
|
|
* @return bool |
2291
|
|
|
* |
2292
|
|
|
* @since 1.0 |
2293
|
|
|
*/ |
2294
|
|
|
public static function isInstalled() |
2295
|
|
|
{ |
2296
|
|
|
if (self::$logger == null) { |
2297
|
|
|
self::$logger = new Logger('ActiveRecord'); |
2298
|
|
|
} |
2299
|
|
|
self::$logger->debug('>>isInstalled()'); |
2300
|
|
|
|
2301
|
|
|
/* |
2302
|
|
|
* Install conditions are: |
2303
|
|
|
* |
2304
|
|
|
* 1. person table exists |
2305
|
|
|
* 2. rights table exists |
2306
|
|
|
*/ |
2307
|
|
|
if (self::checkRecordTableExists('Alpha\Model\Person') && self::checkRecordTableExists('Alpha\Model\Rights')) { |
2308
|
|
|
self::$logger->debug('<<isInstalled [true]'); |
2309
|
|
|
|
2310
|
|
|
return true; |
2311
|
|
|
} else { |
2312
|
|
|
self::$logger->debug('<<isInstalled [false]'); |
2313
|
|
|
|
2314
|
|
|
return false; |
2315
|
|
|
} |
2316
|
|
|
} |
2317
|
|
|
|
2318
|
|
|
/** |
2319
|
|
|
* Returns true if the Record has a Relation property called tags, false otherwise. |
2320
|
|
|
* |
2321
|
|
|
* @return bool |
2322
|
|
|
* |
2323
|
|
|
* @since 1.0 |
2324
|
|
|
*/ |
2325
|
|
|
public function isTagged() |
2326
|
|
|
{ |
2327
|
|
|
if (property_exists($this, 'taggedAttributes') && property_exists($this, 'tags') && $this->{'tags'} instanceof \Alpha\Model\Type\Relation) { |
2328
|
|
|
return true; |
2329
|
|
|
} else { |
2330
|
|
|
return false; |
2331
|
|
|
} |
2332
|
|
|
} |
2333
|
|
|
|
2334
|
|
|
/** |
2335
|
|
|
* Returns the contents of the taggedAttributes array, or an empty array if that does not exist. |
2336
|
|
|
* |
2337
|
|
|
* @return array |
2338
|
|
|
* |
2339
|
|
|
* @since 1.2.3 |
2340
|
|
|
*/ |
2341
|
|
|
public function getTaggedAttributes() |
2342
|
|
|
{ |
2343
|
|
|
if ($this->isTagged()) { |
2344
|
|
|
return $this->{'taggedAttributes'}; |
2345
|
|
|
} else { |
2346
|
|
|
return array(); |
2347
|
|
|
} |
2348
|
|
|
} |
2349
|
|
|
|
2350
|
|
|
/** |
2351
|
|
|
* Setter for the Record version number. |
2352
|
|
|
* |
2353
|
|
|
* @param int $versionNumber The version number. |
2354
|
|
|
* |
2355
|
|
|
* @since 1.0 |
2356
|
|
|
*/ |
2357
|
|
|
private function setVersion($versionNumber) |
2358
|
|
|
{ |
2359
|
|
|
$this->version_num->setValue($versionNumber); |
2360
|
|
|
} |
2361
|
|
|
|
2362
|
|
|
/** |
2363
|
|
|
* Cast a Record to another type of record. A new Record will be returned with the same ID and |
2364
|
|
|
* version_num as the old record, so this is NOT a true cast but is a copy. All attribute |
2365
|
|
|
* values will be copied accross. |
2366
|
|
|
* |
2367
|
|
|
* @param string $targetClassName The fully-qualified name of the target Record class. |
2368
|
|
|
* @param \Alpha\Model\ActiveRecord $originalRecord The original business object. |
2369
|
|
|
* |
2370
|
|
|
* @return \Alpha\Model\ActiveRecord The new business object resulting from the cast. |
2371
|
|
|
* |
2372
|
|
|
* @since 1.0 |
2373
|
|
|
*/ |
2374
|
|
|
public function cast($targetClassName, $originalRecord) |
2375
|
|
|
{ |
2376
|
|
|
$record = new $targetClassName(); |
2377
|
|
|
$record->setID($originalRecord->getID()); |
2378
|
|
|
$record->setVersion($originalRecord->getVersion()); |
2379
|
|
|
|
2380
|
|
|
// get the class attributes |
2381
|
|
|
$originalRecordreflection = new ReflectionClass(get_class($originalRecord)); |
2382
|
|
|
$originalRecordproperties = $originalRecordreflection->getProperties(); |
2383
|
|
|
$newRecordreflection = new ReflectionClass($targetClassName); |
2384
|
|
|
$newRecordproperties = $newRecordreflection->getProperties(); |
2385
|
|
|
|
2386
|
|
|
// copy the property values from the old Record to the new record |
2387
|
|
|
|
2388
|
|
|
if (count($originalRecordproperties) < count($newRecordproperties)) { |
2389
|
|
|
// the original Record is smaller, so loop over its properties |
2390
|
|
|
foreach ($originalRecordproperties as $propObj) { |
2391
|
|
|
$propName = $propObj->name; |
2392
|
|
|
if (!in_array($propName, $this->transientAttributes)) { |
2393
|
|
|
$record->set($propName, $originalRecord->get($propName)); |
2394
|
|
|
} |
2395
|
|
|
} |
2396
|
|
|
} else { |
2397
|
|
|
// the new Record is smaller, so loop over its properties |
2398
|
|
|
foreach ($newRecordproperties as $propObj) { |
2399
|
|
|
$propName = $propObj->name; |
2400
|
|
|
if (!in_array($propName, $this->transientAttributes)) { |
2401
|
|
|
$record->set($propName, $originalRecord->get($propName)); |
2402
|
|
|
} |
2403
|
|
|
} |
2404
|
|
|
} |
2405
|
|
|
|
2406
|
|
|
return $record; |
2407
|
|
|
} |
2408
|
|
|
|
2409
|
|
|
/** |
2410
|
|
|
* Returns the simple class name, stripped of the namespace. |
2411
|
|
|
* |
2412
|
|
|
* @return string |
2413
|
|
|
* |
2414
|
|
|
* @since 1.0 |
2415
|
|
|
*/ |
2416
|
|
|
public function getFriendlyClassName() |
2417
|
|
|
{ |
2418
|
|
|
$reflectClass = new ReflectionClass($this); |
2419
|
|
|
|
2420
|
|
|
return $reflectClass->getShortname(); |
2421
|
|
|
} |
2422
|
|
|
|
2423
|
|
|
/** |
2424
|
|
|
* Check to see if an attribute exists on the record. |
2425
|
|
|
* |
2426
|
|
|
* @param string $attribute The attribute name. |
2427
|
|
|
* |
2428
|
|
|
* @return bool |
2429
|
|
|
* |
2430
|
|
|
* @since 1.0 |
2431
|
|
|
*/ |
2432
|
|
|
public function hasAttribute($attribute) |
2433
|
|
|
{ |
2434
|
|
|
return property_exists($this, $attribute); |
2435
|
|
|
} |
2436
|
|
|
|
2437
|
|
|
/** |
2438
|
|
|
* Stores the business object to the configured cache instance. |
2439
|
|
|
* |
2440
|
|
|
* @since 1.1 |
2441
|
|
|
*/ |
2442
|
|
|
public function addToCache() |
2443
|
|
|
{ |
2444
|
|
|
self::$logger->debug('>>addToCache()'); |
2445
|
|
|
$config = ConfigProvider::getInstance(); |
2446
|
|
|
|
2447
|
|
|
try { |
2448
|
|
|
$cache = ServiceFactory::getInstance($config->get('cache.provider.name'), 'Alpha\Util\Cache\CacheProviderInterface'); |
2449
|
|
|
$cache->set(get_class($this).'-'.$this->getID(), $this, 3600); |
2450
|
|
|
} catch (\Exception $e) { |
2451
|
|
|
self::$logger->error('Error while attempting to store a business object to the ['.$config->get('cache.provider.name').'] |
2452
|
|
|
instance: ['.$e->getMessage().']'); |
2453
|
|
|
} |
2454
|
|
|
|
2455
|
|
|
self::$logger->debug('<<addToCache'); |
2456
|
|
|
} |
2457
|
|
|
|
2458
|
|
|
/** |
2459
|
|
|
* Removes the business object from the configured cache instance. |
2460
|
|
|
* |
2461
|
|
|
* @since 1.1 |
2462
|
|
|
*/ |
2463
|
|
|
public function removeFromCache() |
2464
|
|
|
{ |
2465
|
|
|
self::$logger->debug('>>removeFromCache()'); |
2466
|
|
|
$config = ConfigProvider::getInstance(); |
2467
|
|
|
|
2468
|
|
|
try { |
2469
|
|
|
$cache = ServiceFactory::getInstance($config->get('cache.provider.name'), 'Alpha\Util\Cache\CacheProviderInterface'); |
2470
|
|
|
$cache->delete(get_class($this).'-'.$this->getID()); |
2471
|
|
|
} catch (\Exception $e) { |
2472
|
|
|
self::$logger->error('Error while attempting to remove a business object from ['.$config->get('cache.provider.name').'] |
2473
|
|
|
instance: ['.$e->getMessage().']'); |
2474
|
|
|
} |
2475
|
|
|
|
2476
|
|
|
self::$logger->debug('<<removeFromCache'); |
2477
|
|
|
} |
2478
|
|
|
|
2479
|
|
|
/** |
2480
|
|
|
* Attempts to load the business object from the configured cache instance. |
2481
|
|
|
* |
2482
|
|
|
* @since 1.1 |
2483
|
|
|
* |
2484
|
|
|
* @return bool |
2485
|
|
|
*/ |
2486
|
|
|
public function loadFromCache() |
2487
|
|
|
{ |
2488
|
|
|
self::$logger->debug('>>loadFromCache()'); |
2489
|
|
|
$config = ConfigProvider::getInstance(); |
2490
|
|
|
|
2491
|
|
|
try { |
2492
|
|
|
$cache = ServiceFactory::getInstance($config->get('cache.provider.name'), 'Alpha\Util\Cache\CacheProviderInterface'); |
2493
|
|
|
$record = $cache->get(get_class($this).'-'.$this->getID()); |
2494
|
|
|
|
2495
|
|
|
if (!$record) { |
2496
|
|
|
self::$logger->debug('Cache miss on key ['.get_class($this).'-'.$this->getID().']'); |
2497
|
|
|
self::$logger->debug('<<loadFromCache: [false]'); |
2498
|
|
|
|
2499
|
|
|
return false; |
2500
|
|
|
} else { |
2501
|
|
|
// get the class attributes |
2502
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
2503
|
|
|
$properties = $reflection->getProperties(); |
2504
|
|
|
|
2505
|
|
|
foreach ($properties as $propObj) { |
2506
|
|
|
$propName = $propObj->name; |
2507
|
|
|
|
2508
|
|
|
// filter transient attributes |
2509
|
|
|
if (!in_array($propName, $this->transientAttributes)) { |
2510
|
|
|
$this->set($propName, $record->get($propName, true)); |
2511
|
|
|
} elseif (!$propObj->isPrivate() && isset($this->$propName) && $this->$propName instanceof Relation) { |
2512
|
|
|
$prop = $this->getPropObject($propName); |
2513
|
|
|
|
2514
|
|
|
// handle the setting of ONE-TO-MANY relation values |
2515
|
|
|
if ($prop->getRelationType() == 'ONE-TO-MANY') { |
2516
|
|
|
$this->set($propObj->name, $this->getID()); |
2517
|
|
|
} |
2518
|
|
|
} |
2519
|
|
|
} |
2520
|
|
|
|
2521
|
|
|
self::$logger->debug('<<loadFromCache: [true]'); |
2522
|
|
|
|
2523
|
|
|
return true; |
2524
|
|
|
} |
2525
|
|
|
} catch (\Exception $e) { |
2526
|
|
|
self::$logger->error('Error while attempting to load a business object from ['.$config->get('cache.provider.name').'] |
2527
|
|
|
instance: ['.$e->getMessage().']'); |
2528
|
|
|
|
2529
|
|
|
self::$logger->debug('<<loadFromCache: [false]'); |
2530
|
|
|
|
2531
|
|
|
return false; |
2532
|
|
|
} |
2533
|
|
|
} |
2534
|
|
|
|
2535
|
|
|
/** |
2536
|
|
|
* Sets the last query executed on this business object. |
2537
|
|
|
* |
2538
|
|
|
* @param string $query |
2539
|
|
|
* |
2540
|
|
|
* @since 1.1 |
2541
|
|
|
*/ |
2542
|
|
|
public function setLastQuery($query) |
2543
|
|
|
{ |
2544
|
|
|
self::$logger->sql($query); |
2545
|
|
|
$this->lastQuery = $query; |
2546
|
|
|
} |
2547
|
|
|
|
2548
|
|
|
/** |
2549
|
|
|
* Re-initialize the static logger property on the Record after de-serialize, as PHP does |
2550
|
|
|
* not serialize static properties. |
2551
|
|
|
* |
2552
|
|
|
* @since 1.2 |
2553
|
|
|
*/ |
2554
|
|
|
public function __wakeup() |
2555
|
|
|
{ |
2556
|
|
|
if (self::$logger == null) { |
2557
|
|
|
self::$logger = new Logger(get_class($this)); |
2558
|
|
|
} |
2559
|
|
|
} |
2560
|
|
|
|
2561
|
|
|
/** |
2562
|
|
|
* Sets maintainHistory attribute on this DAO. |
2563
|
|
|
* |
2564
|
|
|
* @param bool $maintainHistory |
2565
|
|
|
* |
2566
|
|
|
* @throws \Alpha\Exception\IllegalArguementException |
2567
|
|
|
* |
2568
|
|
|
* @since 1.2 |
2569
|
|
|
*/ |
2570
|
|
|
public function setMaintainHistory($maintainHistory) |
2571
|
|
|
{ |
2572
|
|
|
if (!is_bool($maintainHistory)) { |
2573
|
|
|
throw new IllegalArguementException('Non-boolean value ['.$maintainHistory.'] passed to setMaintainHistory method!'); |
2574
|
|
|
} |
2575
|
|
|
|
2576
|
|
|
$this->maintainHistory = $maintainHistory; |
2577
|
|
|
} |
2578
|
|
|
|
2579
|
|
|
/** |
2580
|
|
|
* Gets the value of the maintainHistory attribute. |
2581
|
|
|
* |
2582
|
|
|
* @return bool |
2583
|
|
|
* |
2584
|
|
|
* @since 1.2 |
2585
|
|
|
*/ |
2586
|
|
|
public function getMaintainHistory() |
2587
|
|
|
{ |
2588
|
|
|
return $this->maintainHistory; |
2589
|
|
|
} |
2590
|
|
|
|
2591
|
|
|
/** |
2592
|
|
|
* Return a hash array of the object containing attribute names and simplfied values. |
2593
|
|
|
* |
2594
|
|
|
* @return array |
2595
|
|
|
* |
2596
|
|
|
* @since 1.2.4 |
2597
|
|
|
*/ |
2598
|
|
|
public function toArray() |
2599
|
|
|
{ |
2600
|
|
|
// get the class attributes |
2601
|
|
|
$reflection = new ReflectionClass(get_class($this)); |
2602
|
|
|
$properties = $reflection->getProperties(); |
2603
|
|
|
|
2604
|
|
|
$propArray = array(); |
2605
|
|
|
|
2606
|
|
|
foreach ($properties as $propObj) { |
2607
|
|
|
$propName = $propObj->name; |
2608
|
|
|
|
2609
|
|
|
if (!in_array($propName, $this->transientAttributes)) { |
2610
|
|
|
$val = $this->get($propName); |
2611
|
|
|
|
2612
|
|
|
if (is_object($val)) { |
2613
|
|
|
$val = $val->getValue(); |
2614
|
|
|
} |
2615
|
|
|
|
2616
|
|
|
$propArray[$propName] = $val; |
2617
|
|
|
} |
2618
|
|
|
} |
2619
|
|
|
|
2620
|
|
|
return $propArray; |
2621
|
|
|
} |
2622
|
|
|
|
2623
|
|
|
/** |
2624
|
|
|
* Check to see if the configured database exists. |
2625
|
|
|
* |
2626
|
|
|
* @return bool |
2627
|
|
|
* |
2628
|
|
|
* @since 2.0 |
2629
|
|
|
*/ |
2630
|
|
|
public static function checkDatabaseExists() |
2631
|
|
|
{ |
2632
|
|
|
$config = ConfigProvider::getInstance(); |
2633
|
|
|
|
2634
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2635
|
|
|
$provider->setRecord(new Person()); |
2636
|
|
|
|
2637
|
|
|
return $provider->checkDatabaseExists(); |
2638
|
|
|
} |
2639
|
|
|
|
2640
|
|
|
/** |
2641
|
|
|
* Creates the configured database. |
2642
|
|
|
* |
2643
|
|
|
* @throws \Alpha\Exception\AlphaException |
2644
|
|
|
* |
2645
|
|
|
* @since 2.0 |
2646
|
|
|
*/ |
2647
|
|
|
public static function createDatabase() |
2648
|
|
|
{ |
2649
|
|
|
$config = ConfigProvider::getInstance(); |
2650
|
|
|
|
2651
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2652
|
|
|
$provider->setRecord(new Person()); |
2653
|
|
|
$provider->createDatabase(); |
2654
|
|
|
} |
2655
|
|
|
|
2656
|
|
|
/** |
2657
|
|
|
* Drops the configured database. |
2658
|
|
|
* |
2659
|
|
|
* @throws \Alpha\Exception\AlphaException |
2660
|
|
|
* |
2661
|
|
|
* @since 2.0 |
2662
|
|
|
*/ |
2663
|
|
|
public static function dropDatabase() |
2664
|
|
|
{ |
2665
|
|
|
$config = ConfigProvider::getInstance(); |
2666
|
|
|
|
2667
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2668
|
|
|
$provider->setRecord(new Person()); |
2669
|
|
|
$provider->dropDatabase(); |
2670
|
|
|
} |
2671
|
|
|
|
2672
|
|
|
/** |
2673
|
|
|
* Backup the configured database. |
2674
|
|
|
* |
2675
|
|
|
* @param string $targetFile The file that the backup data will be written to. |
2676
|
|
|
* |
2677
|
|
|
* @throws \Alpha\Exception\AlphaException |
2678
|
|
|
* |
2679
|
|
|
* @since 3.0 |
2680
|
|
|
*/ |
2681
|
|
|
public static function backupDatabase($targetFile) |
2682
|
|
|
{ |
2683
|
|
|
$config = ConfigProvider::getInstance(); |
2684
|
|
|
|
2685
|
|
|
$provider = ServiceFactory::getInstance($config->get('db.provider.name'), 'Alpha\Model\ActiveRecordProviderInterface'); |
2686
|
|
|
$provider->setRecord(new Person()); |
2687
|
|
|
$provider->backupDatabase($targetFile); |
2688
|
|
|
} |
2689
|
|
|
} |
2690
|
|
|
|
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.