Overview

Packages

  • alpha::controller
  • alpha::controller::front
  • alpha::exceptions
  • alpha::model
  • alpha::model::types
  • alpha::tasks
  • alpha::tests
  • alpha::util
  • alpha::util::cache
  • alpha::util::codehighlight
  • alpha::util::convertors
  • alpha::util::feeds
  • alpha::util::filters
  • alpha::util::graphs
  • alpha::util::helpers
  • alpha::util::metrics
  • alpha::view
  • alpha::view::renderers
  • alpha::view::widgets

Classes

  • AlphaDAO
  • AlphaDAOProviderFactory
  • AlphaDAOProviderMySQL
  • AlphaDAOProviderSQLite
  • ArticleCommentObject
  • ArticleObject
  • ArticleVoteObject
  • BadRequestObject
  • BlacklistedClientObject
  • BlacklistedIPObject
  • PersonObject
  • RightsObject
  • TagObject

Interfaces

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