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::util::search
  • alpha::view
  • alpha::view::renderers
  • alpha::view::widgets

Classes

  • ActionLogObject
  • 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 1797 2014-07-20 20:28:43Z alphadevx $
  10:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  11:  * @copyright Copyright (c) 2014, 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:                 $this->addToCache();
 470:             }
 471: 
 472:             if(method_exists($this, 'after_save_callback'))
 473:                 $this->after_save_callback();
 474:         }
 475:     }
 476: 
 477:     /**
 478:      * Saves the field specified with the value supplied.  Only works for persistent BOs.  Note that no Alpha type
 479:      * validation is performed with this method!
 480:      *
 481:      * @param string $attribute The name of the attribute to save.
 482:      * @param mixed $value The value of the attribute to save.
 483:      * @since 1.0
 484:      * @throws IllegalArguementException
 485:      * @throws FailedSaveException
 486:      */
 487:     public function saveAttribute($attribute, $value) {
 488:         self::$logger->debug('>>saveAttribute(attribute=['.$attribute.'], value=['.$value.'])');
 489: 
 490:         if(method_exists($this, 'before_saveAttribute_callback'))
 491:             $this->before_saveAttribute_callback();
 492: 
 493:         global $config;
 494: 
 495:         if(!isset($this->$attribute))
 496:             throw new IllegalArguementException('Could not perform save, as the attribute ['.$attribute.'] is not present on the class['.get_class($this).']');
 497: 
 498:         if($this->isTransient())
 499:             throw new FailedSaveException('Cannot perform saveAttribute method on transient BO!');
 500: 
 501:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 502:         $provider->saveAttribute($attribute, $value);
 503: 
 504:         if($config->get('cache.provider.name') != '') {
 505:             $this->removeFromCache();
 506:             $this->addToCache();
 507:         }
 508: 
 509:         if(method_exists($this, 'after_saveAttribute_callback'))
 510:             $this->after_saveAttribute_callback();
 511: 
 512:         self::$logger->debug('<<saveAttribute');
 513:     }
 514: 
 515:     /**
 516:      * Saves the history of the object in the [tablename]_history table. It will always perform an insert.
 517:      *
 518:      * @since 1.2
 519:      * @throws FailedSaveException
 520:      */
 521:     public function saveHistory() {
 522:         self::$logger->debug('>>saveHistory()');
 523: 
 524:         if(method_exists($this, 'before_saveHistory_callback'))
 525:             $this->before_saveHistory_callback();
 526: 
 527:         global $config;
 528: 
 529:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 530:         $provider->saveHistory();
 531: 
 532:         if(method_exists($this, 'after_saveHistory_callback'))
 533:             $this->after_saveHistory_callback();
 534:     }
 535: 
 536:     /**
 537:      * Validates the object to be saved.
 538:      *
 539:      * @return boolean
 540:      * @since 1.0
 541:      * @throws ValidationException
 542:      */
 543:     protected function validate() {
 544:         self::$logger->debug('>>validate()');
 545: 
 546:         if(method_exists($this, 'before_validate_callback'))
 547:             $this->before_validate_callback();
 548: 
 549:         $valid = true;
 550: 
 551:         // get the class attributes
 552:         $reflection = new ReflectionClass(get_class($this));
 553:         $properties = $reflection->getProperties();
 554: 
 555:         foreach($properties as $propObj) {
 556:             $propName = $propObj->name;
 557:             if(!in_array($propName, $this->defaultAttributes) && !in_array($propName, $this->transientAttributes)) {
 558:                 $propClass = get_class($this->getPropObject($propName));
 559:                 if (mb_strtoupper($propClass) != "ENUM" &&
 560:                 mb_strtoupper($propClass) != "DENUM" &&
 561:                 mb_strtoupper($propClass) != "DENUMITEM" &&
 562:                 mb_strtoupper($propClass) != "BOOLEAN") {
 563:                     if ($this->getPropObject($propName) != false && !preg_match($this->getPropObject($propName)->getRule(), $this->getPropObject($propName)->getValue())) {
 564:                         throw new ValidationException('Failed to save, validation error is: '.$this->getPropObject($propName)->getHelper());
 565:                         $valid = false;
 566:                     }
 567:                 }
 568:             }
 569:         }
 570: 
 571:         if(method_exists($this, 'after_validate_callback'))
 572:             $this->after_validate_callback();
 573: 
 574:         self::$logger->debug('<<validate ['.$valid.']');
 575:         return $valid;
 576:     }
 577: 
 578:     /**
 579:      * Deletes the current object from the database.
 580:      *
 581:      * @since 1.0
 582:      * @throws FailedDeleteException
 583:      */
 584:     public function delete() {
 585:         self::$logger->debug('>>delete()');
 586: 
 587:         if(method_exists($this, 'before_delete_callback'))
 588:             $this->before_delete_callback();
 589: 
 590:         global $config;
 591: 
 592:         // get the class attributes
 593:         $reflection = new ReflectionClass(get_class($this));
 594:         $properties = $reflection->getProperties();
 595: 
 596:         // check for any relations on this object, then remove them to prevent orphaned data
 597:         foreach($properties as $propObj) {
 598:             $propName = $propObj->name;
 599: 
 600:             if(!$propObj->isPrivate() && isset($this->$propName) && $this->$propName instanceof Relation) {
 601:                 $prop = $this->getPropObject($propName);
 602: 
 603:                 // Handle MANY-TO-MANY rels
 604:                 if($prop->getRelationType() == 'MANY-TO-MANY') {
 605:                     self::$logger->debug('Deleting MANY-TO-MANY lookup objects...');
 606: 
 607:                     try{
 608:                         // check to see if the rel is on this class
 609:                         $side = $prop->getSide(get_class($this));
 610:                     }catch (IllegalArguementException $iae) {
 611:                         $side = $prop->getSide(ucfirst($this->getTableName()).'Object');
 612:                     }
 613: 
 614:                     self::$logger->debug('Side is ['.$side.']'.$this->getOID());
 615: 
 616:                     $lookUp = $prop->getLookup();
 617:                     self::$logger->debug('Lookup object['.var_export($lookUp, true).']');
 618: 
 619:                     // delete all of the old RelationLookup objects for this rel
 620:                     if($side == 'left')
 621:                         $lookUp->deleteAllByAttribute('leftID', $this->getOID());
 622:                     else
 623:                         $lookUp->deleteAllByAttribute('rightID', $this->getOID());
 624:                     self::$logger->debug('...done deleting!');
 625:                 }
 626: 
 627:                 // should set related field values to null (MySQL is doing this for us as-is)
 628:                 if($prop->getRelationType() == 'ONE-TO-MANY' && !$prop->getRelatedClass() == 'TagObject') {
 629:                     $relatedObjects = $prop->getRelatedObjects();
 630: 
 631:                     foreach($relatedObjects as $object) {
 632:                         $object->set($prop->getRelatedClassField(), null);
 633:                         $object->save();
 634:                     }
 635:                 }
 636: 
 637:                 // in the case of tags, we will always remove the related tags once the BO is deleted
 638:                 if($prop->getRelationType() == 'ONE-TO-MANY' && $prop->getRelatedClass() == 'TagObject') {
 639:                     // just making sure that the Relation is set to current OID as its transient
 640:                     $prop->setValue($this->getOID());
 641:                     $relatedObjects = $prop->getRelatedObjects();
 642: 
 643:                     foreach($relatedObjects as $object) {
 644:                         $object->delete();
 645:                     }
 646:                 }
 647:             }
 648:         }
 649: 
 650:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 651:         $provider->delete();
 652: 
 653:         if($config->get('cache.provider.name') != '')
 654:             $this->removeFromCache();
 655: 
 656:         if(method_exists($this, 'after_delete_callback'))
 657:             $this->after_delete_callback();
 658: 
 659:         $this->clear();
 660:         self::$logger->debug('<<delete');
 661:     }
 662: 
 663:     /**
 664:      * Delete all object instances from the database by the specified attribute matching the value provided.
 665:      *
 666:      * @param string $attribute The name of the field to delete the objects by.
 667:      * @param mixed $value The value of the field to delete the objects by.
 668:      * @return integer The number of rows deleted.
 669:      * @since 1.0
 670:      * @throws FailedDeleteException
 671:      */
 672:     public function deleteAllByAttribute($attribute, $value) {
 673:         self::$logger->debug('>>deleteAllByAttribute(attribute=['.$attribute.'], value=['.$value.'])');
 674: 
 675:         if(method_exists($this, 'before_deleteAllByAttribute_callback'))
 676:             $this->before_deleteAllByAttribute_callback();
 677: 
 678:         try {
 679:             $doomedObjects = $this->loadAllByAttribute($attribute, $value);
 680:             $deletedRowCount = 0;
 681: 
 682:             foreach ($doomedObjects as $object) {
 683:                 $object->delete();
 684:                 $deletedRowCount++;
 685:             }
 686:         }catch (BONotFoundException $bonf) {
 687:             // nothing found to delete
 688:             self::$logger->warn($bonf->getMessage());
 689:             return 0;
 690:         }catch (AlphaException $e) {
 691:             throw new FailedDeleteException('Failed to delete objects, error is ['.$e->getMessage().']');
 692:             self::$logger->debug('<<deleteAllByAttribute [0]');
 693:             return 0;
 694:         }
 695: 
 696:         if(method_exists($this, 'after_deleteAllByAttribute_callback'))
 697:             $this->after_deleteAllByAttribute_callback();
 698: 
 699:         self::$logger->debug('<<deleteAllByAttribute ['.$deletedRowCount.']');
 700:         return $deletedRowCount;
 701:     }
 702: 
 703:     /**
 704:      * Gets the version_num of the object from the database (returns 0 if the BO is not saved yet).
 705:      *
 706:      * @return integer
 707:      * @since 1.0
 708:      * @throws BONotFoundException
 709:      */
 710:     public function getVersion() {
 711:         self::$logger->debug('>>getVersion()');
 712: 
 713:         if(method_exists($this, 'before_getVersion_callback'))
 714:             $this->before_getVersion_callback();
 715: 
 716:         global $config;
 717: 
 718:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 719:         $ver = $provider->getVersion();
 720: 
 721:         if(method_exists($this, 'after_getVersion_callback'))
 722:             $this->after_getVersion_callback();
 723: 
 724:         self::$logger->debug('<<getVersion ['.$ver.']');
 725:         return $ver;
 726:     }
 727: 
 728:     /**
 729:      * Builds a new database table for the BO class.
 730:      *
 731:      * @since 1.0
 732:      * @throws AlphaException
 733:      */
 734:     public function makeTable() {
 735:         self::$logger->debug('>>makeTable()');
 736: 
 737:         if(method_exists($this, 'before_makeTable_callback'))
 738:             $this->before_makeTable_callback();
 739: 
 740:         global $config;
 741: 
 742:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 743:         $provider->makeTable();
 744: 
 745:         if(method_exists($this, 'after_makeTable_callback'))
 746:             $this->after_makeTable_callback();
 747: 
 748:         self::$logger->info('Successfully created the table ['.$this->getTableName().'] for the class ['.get_class($this).']');
 749: 
 750:         self::$logger->debug('<<makeTable');
 751:     }
 752: 
 753:     /**
 754:      * Builds a new database table for the BO class to story it's history of changes
 755:      *
 756:      * @since 1.2
 757:      * @throws AlphaException
 758:      */
 759:     public function makeHistoryTable() {
 760:         self::$logger->debug('>>makeHistoryTable()');
 761: 
 762:         if(method_exists($this, 'before_makeHistoryTable_callback'))
 763:             $this->before_makeHistoryTable_callback();
 764: 
 765:         global $config;
 766: 
 767:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 768:         $provider->makeHistoryTable();
 769: 
 770:         if(method_exists($this, 'after_makeHistoryTable_callback'))
 771:             $this->after_makeHistoryTable_callback();
 772: 
 773:         self::$logger->info('Successfully created the table ['.$this->getTableName().'_history] for the class ['.get_class($this).']');
 774: 
 775:         self::$logger->debug('<<makeHistoryTable');
 776:     }
 777: 
 778:     /**
 779:      * Re-builds the table if the model requirements have changed.  All data is lost!
 780:      *
 781:      * @since 1.0
 782:      * @throws AlphaException
 783:      */
 784:     public function rebuildTable() {
 785:         self::$logger->debug('>>rebuildTable()');
 786: 
 787:         if(method_exists($this, 'before_rebuildTable_callback'))
 788:             $this->before_rebuildTable_callback();
 789: 
 790:         global $config;
 791: 
 792:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 793:         $provider->rebuildTable();
 794: 
 795:         if(method_exists($this, 'after_rebuildTable_callback'))
 796:             $this->after_rebuildTable_callback();
 797: 
 798:         self::$logger->debug('<<rebuildTable');
 799:     }
 800: 
 801:     /**
 802:      * Drops the table if the model requirements have changed.  All data is lost!
 803:      *
 804:      * @since 1.0
 805:      * @param string $tableName Optional table name, leave blank for the defined table for this class to be dropped
 806:      * @throws AlphaException
 807:      */
 808:     public function dropTable($tableName=null) {
 809:         self::$logger->debug('>>dropTable()');
 810: 
 811:         if(method_exists($this, 'before_dropTable_callback'))
 812:             $this->before_dropTable_callback();
 813: 
 814:         global $config;
 815: 
 816:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 817:         $provider->dropTable($tableName);
 818: 
 819:         if(method_exists($this, 'after_dropTable_callback'))
 820:             $this->after_dropTable_callback();
 821: 
 822:         self::$logger->debug('<<dropTable');
 823:     }
 824: 
 825:     /**
 826:      * Adds in a new class property without loosing existing data (does an ALTER TABLE query on the
 827:      * database).
 828:      *
 829:      * @param string $propName The name of the new field to add to the database table.
 830:      * @since 1.0
 831:      * @throws AlphaException
 832:      */
 833:     public function addProperty($propName) {
 834:         self::$logger->debug('>>addProperty(propName=['.$propName.'])');
 835: 
 836:         global $config;
 837: 
 838:         if(method_exists($this, 'before_addProperty_callback'))
 839:             $this->before_addProperty_callback();
 840: 
 841:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 842:         $provider->addProperty($propName);
 843: 
 844:         if(method_exists($this, 'after_addProperty_callback'))
 845:             $this->after_addProperty_callback();
 846: 
 847:         self::$logger->debug('<<addProperty');
 848:     }
 849: 
 850:     /**
 851:      * Populates the current business object from global POST data.
 852:      *
 853:      * @param boolean $filterAll Defaults to false, set to true if you want to strictly filter all POSTed user input using InputFilter::encode.
 854:      * @since 1.0
 855:      */
 856:     public function populateFromPost($filterAll=false) {
 857:         self::$logger->debug('>>populateFromPost(filterAll=['.$filterAll.'])');
 858: 
 859:         if(method_exists($this, 'before_populateFromPost_callback'))
 860:             $this->before_populateFromPost_callback();
 861: 
 862:         // get the class attributes
 863:         $reflection = new ReflectionClass(get_class($this));
 864:         $properties = $reflection->getProperties();
 865: 
 866:         foreach($properties as $propObj) {
 867:             $propName = $propObj->name;
 868: 
 869:             if(!in_array($propName, $this->defaultAttributes) && !in_array($propName, $this->transientAttributes)) {
 870:                 $propClass = get_class($this->getPropObject($propName));
 871: 
 872:                 if(isset($_POST[$propName])) {
 873:                     // we will accept "on" as a valid Boolean when dealing with checkboxes
 874:                     if(mb_strtoupper($propClass) == 'BOOLEAN' && $_POST[$propName] == 'on') {
 875:                         $_POST[$propName] = 1;
 876:                     }
 877: 
 878:                     if (mb_strtoupper($propClass) != 'DATE' && mb_strtoupper($propClass) != 'TIMESTAMP') {
 879:                         if($filterAll) {
 880:                             $this->getPropObject($propName)->setValue(InputFilter::encode($_POST[$propName], false));
 881:                         }else{
 882:                             if(mb_strtoupper($propClass) == 'TEXT' && !$this->getPropObject($propName)->getAllowHTML())
 883:                                 $this->getPropObject($propName)->setValue(InputFilter::encode($_POST[$propName], false));
 884:                             else
 885:                                 $this->getPropObject($propName)->setValue(InputFilter::encode($_POST[$propName], true));
 886:                         }
 887:                     }else{
 888:                         if($filterAll)
 889:                             $this->getPropObject($propName)->populateFromString(InputFilter::encode($_POST[$propName], false));
 890:                         else
 891:                             $this->getPropObject($propName)->populateFromString(InputFilter::encode($_POST[$propName], true));
 892:                     }
 893:                 }
 894:             }
 895:             if ($propName == 'version_num' && isset($_POST['version_num']))
 896:                 $this->version_num->setValue($_POST['version_num']);
 897:         }
 898:         if(method_exists($this, 'after_populateFromPost_callback'))
 899:             $this->after_populateFromPost_callback();
 900: 
 901:         self::$logger->debug('<<populateFromPost');
 902:     }
 903: 
 904:     /**
 905:      * Populates the current business object from the provided hash array
 906:      *
 907:      * @param array $hashArray
 908:      * @since 1.2.1
 909:      */
 910:     public function populateFromArray($hashArray) {
 911:         self::$logger->debug('>>populateFromArray(hashArray=['.print_r($hashArray, true).'])');
 912: 
 913:         // get the class attributes
 914:         $reflection = new ReflectionClass(get_class($this));
 915:         $properties = $reflection->getProperties();
 916: 
 917:         foreach($properties as $propObj) {
 918:             $propName = $propObj->name;
 919: 
 920:             if(!in_array($propName, $this->defaultAttributes) && !in_array($propName, $this->transientAttributes)) {
 921:                 $propClass = get_class($this->getPropObject($propName));
 922: 
 923:                 if(isset($hashArray[$propName])) {
 924: 
 925:                     if (mb_strtoupper($propClass) != 'DATE' && mb_strtoupper($propClass) != 'TIMESTAMP')
 926:                         $this->getPropObject($propName)->setValue($hashArray[$propName]);
 927:                     else
 928:                         $this->getPropObject($propName)->populateFromString($hashArray[$propName]);
 929:                 }
 930:             }
 931: 
 932:             if ($propName == 'version_num' && isset($hashArray['version_num']))
 933:                 $this->version_num->setValue($hashArray['version_num']);
 934:         }
 935: 
 936:         self::$logger->debug('<<populateFromArray');
 937:     }
 938: 
 939:     /**
 940:      * Gets the maximum OID value from the database for this class type.
 941:      *
 942:      * @return integer The maximum OID value in the class table.
 943:      * @since 1.0
 944:      * @throws AlphaException
 945:      */
 946:     public function getMAX() {
 947:         self::$logger->debug('>>getMAX()');
 948: 
 949:         if(method_exists($this, 'before_getMAX_callback'))
 950:             $this->before_getMAX_callback();
 951: 
 952:         global $config;
 953: 
 954:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 955:         $max = $provider->getMAX();
 956: 
 957:         if(method_exists($this, 'after_getMAX_callback'))
 958:             $this->after_getMAX_callback();
 959: 
 960:         self::$logger->debug('<<getMAX ['.$max.']');
 961:         return $max;
 962:     }
 963: 
 964:     /**
 965:      * Gets the count from the database for the amount of objects of this class.
 966:      *
 967:      * @param array $atributes The attributes to count the objects by (optional).
 968:      * @param array $values The values of the attributes to count the objects by (optional).
 969:      * @return integer
 970:      * @since 1.0
 971:      * @throws AlphaException
 972:      */
 973:     public function getCount($attributes=array(), $values=array()) {
 974:         self::$logger->debug('>>getCount(attributes=['.var_export($attributes, true).'], values=['.var_export($values, true).'])');
 975: 
 976:         if(method_exists($this, 'before_getCount_callback'))
 977:             $this->before_getCount_callback();
 978: 
 979:         global $config;
 980: 
 981:         if(!is_array($attributes) || !is_array($values)) {
 982:             throw new IllegalArguementException('Illegal arrays attributes=['.var_export($attributes, true).'] and values=['.var_export($values, true).'] provided to loadAllByAttributes');
 983:         }
 984: 
 985:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
 986:         $count = $provider->getCount($attributes, $values);
 987: 
 988:         if(method_exists($this, 'after_getCount_callback'))
 989:             $this->after_getCount_callback();
 990: 
 991:         self::$logger->debug('<<getCount ['.$count.']');
 992:         return $count;
 993:     }
 994: 
 995:     /**
 996:      * Gets the count from the database for the amount of entries in the [tableName]_history table for this business object.  Only call
 997:      * this method on classes where maintainHistory = true, otherwise an exception will be thrown.
 998:      *
 999:      * @return integer
1000:      * @since 1.2
1001:      * @throws AlphaException
1002:      */
1003:     public function getHistoryCount() {
1004:         self::$logger->debug('>>getHistoryCount()');
1005: 
1006:         if(method_exists($this, 'before_getHistoryCount_callback'))
1007:             $this->before_getHistoryCount_callback();
1008: 
1009:         global $config;
1010: 
1011:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1012:         $count = $provider->getHistoryCount();
1013: 
1014:         if(method_exists($this, 'after_getHistoryCount_callback'))
1015:             $this->after_getHistoryCount_callback();
1016: 
1017:         self::$logger->debug('<<getHistoryCount ['.$count.']');
1018:         return $count;
1019:     }
1020: 
1021:     /**
1022:      * Gets the OID for the object in zero-padded format (same as getOID()).  This version is designed
1023:      * to be overridden in case you want to do something different with the ID of your objects outside
1024:      * of the standard 11 digit OID sequence used internally in Alpha.
1025:      *
1026:      * @return integer 11 digit zero-padded OID value.
1027:      * @since 1.0
1028:      */
1029:     public function getID() {
1030:         self::$logger->debug('>>getID()');
1031:         $oid = str_pad($this->OID, 11, '0', STR_PAD_LEFT);
1032:         self::$logger->debug('<<getID ['.$oid.']');
1033:         return $oid;
1034:     }
1035: 
1036:     /**
1037:      * Gets the OID for the object in zero-padded format (same as getID()).  This version is final so cannot
1038:      * be overridden.
1039:      *
1040:      * @return integer 11 digit zero-padded OID value.
1041:      * @since 1.0
1042:      */
1043:     public final function getOID() {
1044:         if(self::$logger == null)
1045:             self::$logger = new Logger('AlphaDAO');
1046:         self::$logger->debug('>>getOID()');
1047:         $oid = str_pad($this->OID, 11, '0', STR_PAD_LEFT);
1048:         self::$logger->debug('<<getOID ['.$oid.']');
1049:         return $oid;
1050:     }
1051: 
1052:     /**
1053:      * Method for getting version number of the object.
1054:      *
1055:      * @return Integer The object version number.
1056:      * @since 1.0
1057:      */
1058:     public function getVersionNumber() {
1059:         self::$logger->debug('>>getVersionNumber()');
1060:         self::$logger->debug('<<getVersionNumber ['.$this->version_num.']');
1061:         return $this->version_num;
1062:     }
1063: 
1064:     /**
1065:      * Populate all of the enum options for this object from the database.
1066:      *
1067:      * @since 1.0
1068:      * @throws AlphaException
1069:      */
1070:     protected function setEnumOptions() {
1071:         self::$logger->debug('>>setEnumOptions()');
1072: 
1073:         if(method_exists($this, 'before_setEnumOptions_callback'))
1074:             $this->before_setEnumOptions_callback();
1075: 
1076:         global $config;
1077: 
1078:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1079:         try {
1080:             $provider->setEnumOptions();
1081:         }catch (NotImplementedException $e) {
1082:             self::$logger->info($e->getMessage());
1083:         }
1084: 
1085:         self::$logger->debug('<<setEnumOptions');
1086:     }
1087: 
1088:     /**
1089:      * Generic getter method for accessing class properties.  Will use the method get.ucfirst($prop) instead if that
1090:      * method exists at a child level (by default).  Set $noChildMethods to true if you don't want to use any 
1091:      * get.ucfirst($prop) method even if it exists, false otherwise (default).
1092:      *
1093:      * @param string $prop The name of the object property to get.
1094:      * @param boolean $noChildMethods Set to true if you do not want to use getters in the child object, defaults to false.
1095:      * @return mixed The property value.
1096:      * @since 1.0
1097:      * @throws IllegalArguementException
1098:      * @throws AlphaException
1099:      */
1100:     public function get($prop, $noChildMethods = false) {
1101:         if(self::$logger == null)
1102:             self::$logger = new Logger('AlphaDAO');
1103: 
1104:         self::$logger->debug('>>get(prop=['.$prop.'], noChildMethods=['.$noChildMethods.'])');
1105: 
1106:         if(method_exists($this, 'before_get_callback'))
1107:             $this->before_get_callback();
1108: 
1109:         if(empty($prop))
1110:             throw new IllegalArguementException('Cannot call get with empty $prop arguement!');
1111: 
1112:         // handle attributes with a get.ucfirst($prop) method
1113:         if(!$noChildMethods && method_exists($this, 'get'.ucfirst($prop))) {
1114:             if(method_exists($this, 'after_get_callback'))
1115:                 $this->after_get_callback();
1116: 
1117:             self::$logger->debug('<<get ['.eval('return print_r($this->get'.ucfirst($prop).'(), true);').'])');
1118:             return eval('return $this->get'.ucfirst($prop).'();');
1119:         }else{
1120:             // handle attributes with no dedicated child get.ucfirst($prop) method
1121:             if(isset($this->$prop) && is_object($this->$prop) && method_exists($this->$prop, 'getValue')) {
1122:                 if(method_exists($this, 'after_get_callback'))
1123:                     $this->after_get_callback();
1124: 
1125:                 // complex types will have a getValue() method, return the value of that
1126:                 self::$logger->debug('<<get ['.$this->$prop->getValue().'])');
1127:                 return $this->$prop->getValue();
1128:             }elseif(isset($this->$prop)) {
1129:                 if(method_exists($this, 'after_get_callback'))
1130:                     $this->after_get_callback();
1131: 
1132:                 // simple types returned as-is
1133:                 self::$logger->debug('<<get ['.print_r($this->$prop, true).'])');
1134:                 return $this->$prop;
1135:             }else{
1136:                 throw new AlphaException('Could not access the property ['.$prop.'] on the object of class ['.get_class($this).']');
1137:                 self::$logger->debug('<<get [false])');
1138:                 return false;
1139:             }
1140:         }
1141:     }
1142: 
1143:     /**
1144:      * Generic setter method for setting class properties.  Will use the method set.ucfirst($prop) instead if that
1145:      * method exists at a child level (by default).  Set $noChildMethods to true if you don't want to use
1146:      * any get.ucfirst($prop) method even if it exists, false otherwise (default).
1147:      *
1148:      * @param string $prop The name of the property to set.
1149:      * @param mixed $value The value of the property to set.
1150:      * @param boolean $noChildMethods Set to true if you do not want to use setters in the child object, defaults
1151:      * to false.
1152:      * @since 1.0
1153:      * @throws AlphaException
1154:      */
1155:     public function set($prop, $value, $noChildMethods = false) {
1156:         self::$logger->debug('>>set(prop=['.$prop.'], $value=['.print_r($value, true).'], noChildMethods=['.$noChildMethods.'])');
1157: 
1158:         if(method_exists($this, 'before_set_callback'))
1159:             $this->before_set_callback();
1160: 
1161:         // handle attributes with a set.ucfirst($prop) method
1162:         if(!$noChildMethods && method_exists($this, 'set'.ucfirst($prop))) {
1163:             if(method_exists($this, 'after_set_callback'))
1164:                 $this->after_set_callback();
1165: 
1166:             eval('$this->set'.ucfirst($prop).'($value);');
1167:         }else{
1168:             // handle attributes with no dedicated child set.ucfirst($prop) method
1169:             if(isset($this->$prop)) {
1170:                 if(method_exists($this, 'after_set_callback'))
1171:                     $this->after_set_callback();
1172: 
1173:                 // complex types will have a setValue() method to call
1174:                 if (is_object($this->$prop) && get_class($this->$prop) != false) {
1175:                     if (mb_strtoupper(get_class($this->$prop)) != 'DATE' && mb_strtoupper(get_class($this->$prop)) != 'TIMESTAMP') {
1176:                         $this->$prop->setValue($value);
1177:                     }else{
1178:                         // Date and Timestamp objects have a special setter accepting a string
1179:                         $this->$prop->populateFromString($value);
1180:                     }
1181:                 }else{
1182:                     // simple types set directly
1183:                     $this->$prop = $value;
1184:                 }
1185:             }else{
1186:                 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.');
1187:             }
1188:         }
1189:         self::$logger->debug('<<set');
1190:     }
1191: 
1192:     /**
1193:      * Gets the property object rather than the value for complex attributes.  Returns false if
1194:      * the property exists but is private.
1195:      *
1196:      * @param string $prop The name of the property we are getting.
1197:      * @return AlphaType The complex type object found.
1198:      * @since 1.0
1199:      * @throws IllegalArguementException
1200:      */
1201:     public function getPropObject($prop) {
1202:         self::$logger->debug('>>getPropObject(prop=['.$prop.'])');
1203: 
1204:         if(method_exists($this, 'before_getPropObject_callback'))
1205:             $this->before_getPropObject_callback();
1206: 
1207:         // get the class attributes
1208:         $reflection = new ReflectionClass(get_class($this));
1209:         $properties = $reflection->getProperties();
1210: 
1211:         // firstly, check for private
1212:         $attribute = new ReflectionProperty(get_class($this), $prop);
1213: 
1214:         if($attribute->isPrivate()) {
1215:             if(method_exists($this, 'after_getPropObject_callback'))
1216:                 $this->after_getPropObject_callback();
1217: 
1218:             self::$logger->debug('<<getPropObject [false]');
1219:             return false;
1220:         }
1221: 
1222:         foreach($properties as $propObj) {
1223:             $propName = $propObj->name;
1224: 
1225:             if($prop == $propName) {
1226:                 if(method_exists($this, 'after_getPropObject_callback'))
1227:                     $this->after_getPropObject_callback();
1228: 
1229:                 self::$logger->debug('<<getPropObject ['.var_export($this->$prop, true).']');
1230:                 return $this->$prop;
1231:             }
1232:         }
1233:         throw new IllegalArguementException('Could not access the property object ['.$prop.'] on the object of class ['.get_class($this).']');
1234:         self::$logger->debug('<<getPropObject [false]');
1235:         return false;
1236:     }
1237: 
1238:     /**
1239:      * Checks to see if the table exists in the database for the current business class.
1240:      *
1241:      * @param boolean $checkHistoryTable Set to true if you want to check for the existance of the _history table for this DAO.
1242:      * @return boolean
1243:      * @since 1.0
1244:      * @throws AlphaException
1245:      */
1246:     public function checkTableExists($checkHistoryTable = false) {
1247:         self::$logger->debug('>>checkTableExists()');
1248: 
1249:         if(method_exists($this, 'before_checkTableExists_callback'))
1250:             $this->before_checkTableExists_callback();
1251: 
1252:         global $config;
1253: 
1254:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1255:         $tableExists = $provider->checkTableExists($checkHistoryTable);
1256: 
1257:         if(method_exists($this, 'after_checkTableExists_callback'))
1258:             $this->after_checkTableExists_callback();
1259: 
1260:         self::$logger->debug('<<checkTableExists ['.$tableExists.']');
1261:         return $tableExists;
1262:     }
1263: 
1264:     /**
1265:      * Static method to check the database and see if the table for the indicated BO class name
1266:      * exists (assumes table name will be $BOClassName less "Object").
1267:      *
1268:      * @param string $BOClassName The name of the business object class we are checking.
1269:      * @param boolean $checkHistoryTable Set to true if you want to check for the existance of the _history table for this DAO.
1270:      * @return boolean
1271:      * @since 1.0
1272:      * @throws AlphaException
1273:      */
1274:     public static function checkBOTableExists($BOClassName, $checkHistoryTable = false) {
1275:         if(self::$logger == null)
1276:             self::$logger = new Logger('AlphaDAO');
1277:         self::$logger->debug('>>checkBOTableExists(BOClassName=['.$BOClassName.'])');
1278: 
1279:         global $config;
1280: 
1281:         require_once $config->get('app.root').'alpha/model/'.$config->get('db.provider.name').'.inc';
1282:         eval('$tableExists = '.$config->get('db.provider.name').'::checkBOTableExists($BOClassName, $checkHistoryTable);');
1283: 
1284:         self::$logger->debug('<<checkBOTableExists ['.($tableExists ? 'true' : 'false').']');
1285:         return $tableExists;
1286:     }
1287: 
1288:     /**
1289:      * Checks to see if the table in the database matches (for fields) the business class definition, i.e. if the
1290:      * database table is in sync with the class definition.
1291:      *
1292:      * @return boolean
1293:      * @since 1.0
1294:      * @throws AlphaException
1295:      */
1296:     public function checkTableNeedsUpdate() {
1297:         self::$logger->debug('>>checkTableNeedsUpdate()');
1298: 
1299:         global $config;
1300: 
1301:         if(method_exists($this, 'before_checkTableNeedsUpdate_callback'))
1302:             $this->before_checkTableNeedsUpdate_callback();
1303: 
1304:         $tableExists = $this->checkTableExists();
1305: 
1306:         if (!$tableExists) {
1307:             self::$logger->debug('<<checkTableNeedsUpdate [true]');
1308:             return true;
1309:         }else{
1310: 
1311:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1312:             $updateRequired = $provider->checkTableNeedsUpdate();
1313: 
1314:             if(method_exists($this, 'after_checkTableNeedsUpdate_callback'))
1315:                 $this->after_checkTableNeedsUpdate_callback();
1316: 
1317:             self::$logger->debug('<<checkTableNeedsUpdate ['.$updateRequired.']');
1318:             return $updateRequired;
1319:         }
1320:     }
1321: 
1322:     /**
1323:      * Returns an array containing any properties on the class which have not been created on the database 
1324:      * table yet.
1325:      *
1326:      * @return array An array of missing fields in the database table.
1327:      * @since 1.0
1328:      * @throws AlphaException
1329:      */
1330:     public function findMissingFields() {
1331:         self::$logger->debug('>>findMissingFields()');
1332: 
1333:         global $config;
1334: 
1335:         if(method_exists($this, 'before_findMissingFields_callback'))
1336:             $this->before_findMissingFields_callback();
1337: 
1338:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1339:         $missingFields = $provider->findMissingFields();
1340: 
1341:         if(method_exists($this, 'after_findMissingFields_callback'))
1342:             $this->after_findMissingFields_callback();
1343: 
1344:         self::$logger->debug('<<findMissingFields ['.var_export($missingFields, true).']');
1345:         return $missingFields;
1346:     }
1347: 
1348:     /**
1349:      * Getter for the TABLE_NAME, which should be set by a child of this class.
1350:      *
1351:      * @return string The table name in the database.
1352:      * @since 1.0
1353:      * @throws AlphaException
1354:      */
1355:     public function getTableName() {
1356:         self::$logger->debug('>>getTableName()');
1357: 
1358:         eval('$TABLE_NAME = '.get_class($this).'::TABLE_NAME;');
1359: 
1360:         if(!empty($TABLE_NAME)) {
1361:             self::$logger->debug('<<getTableName ['.$TABLE_NAME.']');
1362:             return $TABLE_NAME;
1363:         }else{
1364:             throw new AlphaException('Error: no TABLE_NAME constant set for the class '.get_class($this));
1365:             self::$logger->debug('<<getTableName []');
1366:             return '';
1367:         }
1368:     }
1369: 
1370:     /**
1371:      * Method for getting the OID of the person who created this BO.
1372:      *
1373:      * @return Integer The OID of the creator.
1374:      * @since 1.0
1375:      */
1376:     public function getCreatorId() {
1377:         self::$logger->debug('>>getCreatorId()');
1378:         self::$logger->debug('<<getCreatorId ['.$this->created_by.']');
1379:         return $this->created_by;
1380:     }
1381: 
1382:     /**
1383:      * Method for getting the OID of the person who updated this BO.
1384:      *
1385:      * @return Integer The OID of the updator.
1386:      * @since 1.0
1387:      */
1388:     public function getUpdatorId() {
1389:         self::$logger->debug('>>getUpdatorId()');
1390:         self::$logger->debug('<<getUpdatorId ['.$this->updated_by.']');
1391:         return $this->updated_by;
1392:     }
1393: 
1394:     /**
1395:      * Method for getting the date/time of when the BO was created.
1396:      *
1397:      * @return Timestamp
1398:      * @since 1.0
1399:      */
1400:     public function getCreateTS() {
1401:         self::$logger->debug('>>getCreateTS()');
1402:         self::$logger->debug('<<getCreateTS ['.$this->created_ts.']');
1403:         return $this->created_ts;
1404:     }
1405: 
1406:     /**
1407:      * Method for getting the date/time of when the BO was last updated.
1408:      *
1409:      * @return Timestamp
1410:      * @since 1.0
1411:      */
1412:     public function getUpdateTS() {
1413:         self::$logger->debug('>>getUpdateTS()');
1414:         self::$logger->debug('<<getUpdateTS ['.$this->updated_ts.']');
1415:         return $this->updated_ts;
1416:     }
1417: 
1418:     /**
1419:      * Adds the name of the attribute provided to the list of transient (non-saved) attributes for this BO.
1420:      *
1421:      * @param string $attributeName The name of the attribute to not save.
1422:      * @since 1.0
1423:      */
1424:     public function markTransient($attributeName) {
1425:         self::$logger->debug('>>markTransient(attributeName=['.$attributeName.'])');
1426:         self::$logger->debug('<<markTransient');
1427:         array_push($this->transientAttributes, $attributeName);
1428:     }
1429: 
1430:     /**
1431:      * Removes the name of the attribute provided from the list of transient (non-saved) attributes for this BO, 
1432:      * ensuring that it will be saved on the next attempt.
1433:      *
1434:      * @param string $attributeName The name of the attribute to save.
1435:      * @since 1.0
1436:      */
1437:     public function markPersistent($attributeName) {
1438:         self::$logger->debug('>>markPersistent(attributeName=['.$attributeName.'])');
1439:         self::$logger->debug('<<markPersistent');
1440:         $this->transientAttributes = array_diff($this->transientAttributes, array($attributeName));
1441:     }
1442: 
1443:     /**
1444:      * Adds the name of the attribute(s) provided to the list of unique (constrained) attributes for this BO.
1445:      *
1446:      * @param string $attribute1Name The first attribute to mark unique in the database.
1447:      * @param string $attribute2Name The second attribute to mark unique in the databse (optional, use only for composite keys).
1448:      * @param string $attribute3Name The third attribute to mark unique in the databse (optional, use only for composite keys).
1449:      * @since 1.0
1450:      */
1451:     protected function markUnique($attribute1Name, $attribute2Name='', $attribute3Name='') {
1452:         self::$logger->debug('>>markUnique(attribute1Name=['.$attribute1Name.'], attribute2Name=['.$attribute2Name.'], attribute3Name=['.$attribute3Name.'])');
1453: 
1454:         if(empty($attribute2Name)) {
1455:             array_push($this->uniqueAttributes, $attribute1Name);
1456:         }else{
1457:             // Process composite unique keys: add them seperated by a + sign
1458:             if($attribute3Name == '')
1459:                 $attributes = $attribute1Name.'+'.$attribute2Name;
1460:             else
1461:                 $attributes = $attribute1Name.'+'.$attribute2Name.'+'.$attribute3Name;
1462: 
1463:             array_push($this->uniqueAttributes, $attributes);
1464:         }
1465: 
1466:         self::$logger->debug('<<markUnique');
1467:     }
1468: 
1469:     /**
1470:      * Returns the array of names of unique attributes on this BO
1471:      *
1472:      * @return array
1473:      * @since 1.1
1474:      */
1475:     public function getUniqueAttributes() {
1476:         self::$logger->debug('>>getUniqueAttributes()');
1477:         self::$logger->debug('<<getUniqueAttributes: ['.print_r($this->uniqueAttributes, true).']');
1478:         return $this->uniqueAttributes;
1479:     }
1480: 
1481:     /**
1482:      * Gets an array of all of the names of the active database indexes for this class.
1483:      *
1484:      * @return array An array of database indexes on this table.
1485:      * @since 1.0
1486:      * @throws AlphaException
1487:      */
1488:     public function getIndexes() {
1489:         self::$logger->debug('>>getIndexes()');
1490: 
1491:         global $config;
1492: 
1493:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1494:         $indexNames = $provider->getIndexes();
1495: 
1496:         self::$logger->debug('<<getIndexes ['.print_r($indexNames, true).']');
1497:         return $indexNames;
1498:     }
1499: 
1500:     /**
1501:      * Creates a foreign key constraint (index) in the database on the given attribute.
1502:      *
1503:      * @param string $attributeName The name of the attribute to apply the index on.
1504:      * @param string $relatedClass The name of the related class in the format "NameObject".
1505:      * @param string $relatedClassAttribute The name of the field to relate to on the related class.
1506:      * @param bool $allowNullValues For foreign key indexes that don't allow null values, set this to false (default is true).
1507:      * @since 1.0
1508:      * @throws FailedIndexCreateException
1509:      */
1510:     public function createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute) {
1511:         self::$logger->debug('>>createForeignIndex(attributeName=['.$attributeName.'], relatedClass=['.$relatedClass.'], relatedClassAttribute=['.$relatedClassAttribute.']');
1512: 
1513:         global $config;
1514: 
1515:         if(method_exists($this, 'before_createForeignIndex_callback'))
1516:             $this->before_createForeignIndex_callback();
1517: 
1518:         AlphaDAO::loadClassDef($relatedClass);
1519:         $relatedBO = new $relatedClass;
1520:         $tableName = $relatedBO->getTableName();
1521: 
1522:         // if the relation is on itself (table-wise), exit without attempting to create the foreign keys
1523:         if($this->getTableName() == $tableName) {
1524:             self::$logger->debug('<<createForeignIndex');
1525:             return;
1526:         }
1527: 
1528:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1529:         $provider->createForeignIndex($attributeName, $relatedClass, $relatedClassAttribute);
1530: 
1531:         if(method_exists($this, 'after_createForeignIndex_callback'))
1532:             $this->after_createForeignIndex_callback();
1533: 
1534:         self::$logger->debug('<<createForeignIndex');
1535:     }
1536: 
1537:     /**
1538:      * Creates a unique index in the database on the given attribute(s).
1539:      *
1540:      * @param string $attribute1Name The first attribute to mark unique in the database.
1541:      * @param string $attribute2Name The second attribute to mark unique in the databse (optional, use only for composite keys).
1542:      * @param string $attribute3Name The third attribute to mark unique in the databse (optional, use only for composite keys).
1543:      * @since 1.0
1544:      * @throws FailedIndexCreateException
1545:      */
1546:     public function createUniqueIndex($attribute1Name, $attribute2Name = '', $attribute3Name = '') {
1547:         self::$logger->debug('>>createUniqueIndex(attribute1Name=['.$attribute1Name.'], attribute2Name=['.$attribute2Name.'], attribute3Name=['.$attribute3Name.'])');
1548: 
1549:         if(method_exists($this, 'before_createUniqueIndex_callback'))
1550:             $this->before_createUniqueIndex_callback();
1551: 
1552:         global $config;
1553: 
1554:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1555:         $provider->createUniqueIndex($attribute1Name, $attribute2Name, $attribute3Name);
1556: 
1557:         if(method_exists($this, 'after_createUniqueIndex_callback'))
1558:             $this->before_createUniqueIndex_callback();
1559: 
1560:         self::$logger->debug('<<createUniqueIndex');
1561:     }
1562: 
1563:     /**
1564:      * Gets the data labels array.
1565:      *
1566:      * @return array An array of attribute labels.
1567:      * @since 1.0
1568:      */
1569:     public function getDataLabels() {
1570:         self::$logger->debug('>>getDataLabels()');
1571:         self::$logger->debug('<<getDataLabels() ['.var_export($this->dataLabels, true).'])');
1572:         return $this->dataLabels;
1573:     }
1574: 
1575:     /**
1576:      * Sets the data labels array.
1577:      *
1578:      * @param array $labels
1579:      * @throws IllegalArguementException
1580:      * @since 1.2
1581:      */
1582:     public function setDataLabels($labels) {
1583:         self::$logger->debug('>>setDataLabels(labels=['.print_r($labels, true).'])');
1584: 
1585:         if(is_array($labels))
1586:             $this->dataLabels = $labels;
1587:         else
1588:             throw new IllegalArguementException('The value ['.print_r($labels, true).'] provided to setDataLabels() is not a valid array!');
1589: 
1590:         self::$logger->debug('<<setDataLabels()');
1591:     }
1592: 
1593:     /**
1594:      * Gets the data label for the given attribute name.
1595:      *
1596:      * @param $att The attribute name to get the label for.
1597:      * @return string
1598:      * @since 1.0
1599:      * @throws IllegalArguementException
1600:      */
1601:     public function getDataLabel($att) {
1602:         self::$logger->debug('>>getDataLabel(att=['.$att.'])');
1603: 
1604:         if(in_array($att, array_keys($this->dataLabels))) {
1605:             self::$logger->debug('<<getDataLabel ['.$this->dataLabels[$att].'])');
1606:             return $this->dataLabels[$att];
1607:         }else{
1608:             throw new IllegalArguementException('No data label found on the class ['.get_class($this).'] for the attribute ['.$att.']');
1609:             self::$logger->debug('<<getDataLabel [])');
1610:             return '';
1611:         }
1612:     }
1613: 
1614:     /**
1615:      * Loops over the core and custom BO directories and builds an array of all of the BO class names in the system.
1616:      *
1617:      * @return array An array of business object class names.
1618:      * @since 1.0
1619:      */
1620:     public static function getBOClassNames() {
1621:         if(self::$logger == null)
1622:             self::$logger = new Logger('AlphaDAO');
1623:         self::$logger->debug('>>getBOClassNames()');
1624: 
1625:         global $config;
1626: 
1627:         $classNameArray = array();
1628: 
1629: 
1630:         if(file_exists($config->get('app.root').'model')) { // it is possible it has not been created yet...
1631:             // first get any custom BOs
1632:             $handle = opendir($config->get('app.root').'model');
1633: 
1634:             // loop over the business object directory
1635:             while (false !== ($file = readdir($handle))) {
1636:                 if (preg_match("/Object.inc/", $file)) {
1637:                     $classname = mb_substr($file, 0, -4);
1638: 
1639:                     array_push($classNameArray, $classname);
1640:                 }
1641:             }
1642:         }
1643: 
1644:         // now loop over the core BOs provided with Alpha
1645: 
1646:         $handle = opendir($config->get('app.root').'alpha/model');
1647: 
1648:         // loop over the business object directory
1649:         while (false !== ($file = readdir($handle))) {
1650:             if (preg_match("/Object.inc/", $file)) {
1651:                 $classname = mb_substr($file, 0, -4);
1652: 
1653:                 array_push($classNameArray, $classname);
1654:             }
1655:         }
1656: 
1657:         asort($classNameArray);
1658:         self::$logger->debug('<<getBOClassNames ['.var_export($classNameArray, true).']');
1659:         return $classNameArray;
1660:     }
1661: 
1662:     /**
1663:      * Get the array of default attribute names.
1664:      *
1665:      * @return array An array of attribute names.
1666:      * @since 1.0
1667:      */
1668:     public function getDefaultAttributes() {
1669:         self::$logger->debug('>>getDefaultAttributes()');
1670:         self::$logger->debug('<<getDefaultAttributes ['.var_export($this->defaultAttributes, true).']');
1671:         return $this->defaultAttributes;
1672:     }
1673: 
1674:     /**
1675:      * Get the array of transient attribute names.
1676:      *
1677:      * @return array An array of attribute names.
1678:      * @since 1.0
1679:      */
1680:     public function getTransientAttributes() {
1681:         self::$logger->debug('>>getTransientAttributes()');
1682:         self::$logger->debug('<<getTransientAttributes ['.var_export($this->transientAttributes, true).']');
1683:         return $this->transientAttributes;
1684:     }
1685: 
1686:     /**
1687:      * Get the array of persistent attribute names, i.e. those that are saved in the database.
1688:      *
1689:      * @return array An array of attribute names.
1690:      * @since 1.0
1691:      */
1692:     public function getPersistentAttributes() {
1693:         self::$logger->debug('>>getPersistentAttributes()');
1694: 
1695:         $attributes = array();
1696: 
1697:         // get the class attributes
1698:         $reflection = new ReflectionClass(get_class($this));
1699:         $properties = $reflection->getProperties();
1700: 
1701:         foreach($properties as $propObj) {
1702:             $propName = $propObj->name;
1703: 
1704:             // filter transient attributes
1705:             if(!in_array($propName, $this->transientAttributes)) {
1706:                 array_push($attributes, $propName);
1707:             }
1708:         }
1709: 
1710:         self::$logger->debug('<<getPersistentAttributes ['.var_export($attributes, true).']');
1711:         return $attributes;
1712:     }
1713: 
1714:     /**
1715:      * Setter for the Object ID (OID)
1716:      *
1717:      * @param integer $OID The Object ID.
1718:      * @since 1.0
1719:      */
1720:     public function setOID($OID) {
1721:         self::$logger->debug('>>setOID(OID=['.$OID.'])');
1722:         self::$logger->debug('<<setOID');
1723:         $this->OID = $OID;
1724:     }
1725: 
1726:     /**
1727:      * Inspector to see if the business object is transient (not presently stored in the database).
1728:      *
1729:      * @return boolean
1730:      * @since 1.0
1731:      */
1732:     public function isTransient() {
1733:         self::$logger->debug('>>isTransient()');
1734: 
1735:         if(empty($this->OID) || !isset($this->OID) || $this->OID == '00000000000') {
1736:             self::$logger->debug('<<isTransient [true]');
1737:             return true;
1738:         }else{
1739:             self::$logger->debug('<<isTransient [false]');
1740:             return false;
1741:         }
1742:     }
1743: 
1744:     /**
1745:      * Get the last database query run on this object.
1746:      *
1747:      * @return string An SQL query string.
1748:      * @since 1.0
1749:      */
1750:     public function getLastQuery() {
1751:         self::$logger->debug('>>getLastQuery()');
1752:         self::$logger->debug('<<getLastQuery ['.$this->lastQuery.']');
1753:         return $this->lastQuery;
1754:     }
1755: 
1756:     /**
1757:      * Unsets all of the attributes of this object to null.
1758:      *
1759:      * @since 1.0
1760:      */
1761:     private function clear() {
1762:         self::$logger->debug('>>clear()');
1763: 
1764:         // get the class attributes
1765:         $reflection = new ReflectionClass(get_class($this));
1766:         $properties = $reflection->getProperties();
1767: 
1768:         foreach($properties as $propObj) {
1769:             $propName = $propObj->name;
1770:             if(!$propObj->isPrivate())
1771:                 unset($this->$propName);
1772:         }
1773: 
1774:         self::$logger->debug('<<clear');
1775:     }
1776: 
1777:     /**
1778:      * Reloads the object from the database, overwritting any attribute values in memory.
1779:      *
1780:      * @since 1.0
1781:      * @throws AlphaException
1782:      */
1783:     public function reload() {
1784:         self::$logger->debug('>>reload()');
1785: 
1786:         if(!$this->isTransient()) {
1787:             $this->load($this->getOID());
1788:         }else{
1789:             throw new AlphaException('Cannot reload transient object from database!');
1790:         }
1791:         self::$logger->debug('<<reload');
1792:     }
1793: 
1794:     /**
1795:      * Loads the definition from the file system for the BO class name provided.
1796:      *
1797:      * @param string $classname The name of the business object class name.
1798:      * @since 1.0
1799:      * @throws IllegalArguementException
1800:      */
1801:     public static function loadClassDef($classname) {
1802:         if(self::$logger == null)
1803:             self::$logger = new Logger('AlphaDAO');
1804:         self::$logger->debug('>>loadClassDef(classname=['.$classname.'])');
1805: 
1806:         global $config;
1807: 
1808:         if(file_exists($config->get('app.root').'model/'.$classname.'.inc'))
1809:             require_once $config->get('app.root').'model/'.$classname.'.inc';
1810:         elseif(file_exists($config->get('app.root').'alpha/model/'.$classname.'.inc'))
1811:             require_once $config->get('app.root').'alpha/model/'.$classname.'.inc';
1812:         elseif(file_exists($config->get('app.root').'alpha/model/types/'.$classname.'.inc'))
1813:             require_once $config->get('app.root').'alpha/model/types/'.$classname.'.inc';
1814:         else
1815:             throw new IllegalArguementException('The class ['.$classname.'] is not defined anywhere!');
1816: 
1817:         self::$logger->debug('<<loadClassDef');
1818:     }
1819: 
1820:     /**
1821:      * Checks if the definition for the BO class name provided exists on the file system.
1822:      *
1823:      * @param string $classname The name of the business object class name.
1824:      * @return boolean
1825:      * @since 1.0
1826:      */
1827:     public static function checkClassDefExists($classname) {
1828:         if(self::$logger == null)
1829:             self::$logger = new Logger('AlphaDAO');
1830:         self::$logger->debug('>>checkClassDefExists(classname=['.$classname.'])');
1831: 
1832:         global $config;
1833: 
1834:         $exists = false;
1835: 
1836:         if(file_exists($config->get('app.root').'model/'.$classname.'.inc'))
1837:             $exists = true;
1838:         if(file_exists($config->get('app.root').'alpha/model/'.$classname.'.inc'))
1839:             $exists = true;
1840:         if(file_exists($config->get('app.root').'alpha/model/types/'.$classname.'.inc'))
1841:             $exists = true;
1842: 
1843:         self::$logger->debug('<<checkClassDefExists ['.$exists.']');
1844:         return $exists;
1845:     }
1846: 
1847:     /**
1848:      * Checks that a record exists for the BO in the database.
1849:      *
1850:      * @param int $OID The Object ID of the object we want to see whether it exists or not.
1851:      * @return boolean
1852:      * @since 1.0
1853:      * @throws AlphaException
1854:      */
1855:     public function checkRecordExists($OID) {
1856:         self::$logger->debug('>>checkRecordExists(OID=['.$OID.'])');
1857: 
1858:         if(method_exists($this, 'before_checkRecordExists_callback'))
1859:             $this->before_checkRecordExists_callback();
1860: 
1861:         global $config;
1862: 
1863:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1864:         $recordExists = $provider->checkRecordExists($OID);
1865: 
1866:         if(method_exists($this, 'after_checkRecordExists_callback'))
1867:             $this->after_checkRecordExists_callback();
1868: 
1869:         self::$logger->debug('<<checkRecordExists ['.$recordExists.']');
1870:         return $recordExists;
1871:     }
1872: 
1873:     /**
1874:      * Checks to see if the table name matches the classname, and if not if the table
1875:      * name matches the classname name of another BO, i.e. the table is used to store 
1876:      * multiple types of BOs.
1877:      *
1878:      * @return bool
1879:      * @since 1.0
1880:      * @throws BadBOTableNameException
1881:      */
1882:     public function isTableOverloaded() {
1883:         self::$logger->debug('>>isTableOverloaded()');
1884: 
1885:         global $config;
1886: 
1887:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
1888:         $isOverloaded = $provider->isTableOverloaded();
1889: 
1890:         self::$logger->debug('<<isTableOverloaded ['.$isOverloaded.']');
1891:         return $isOverloaded;
1892:     }
1893: 
1894:     /**
1895:      * Starts a new database transaction.
1896:      *
1897:      * @param $BO The AlphaDAO instance to pass to the database provider. Leave empty to have a new PersonObject passed.
1898:      * @since 1.0
1899:      * @throws AlphaException
1900:      */
1901:     public static function begin($BO = null) {
1902:         if(self::$logger == null)
1903:             self::$logger = new Logger('AlphaDAO');
1904:         self::$logger->debug('>>begin()');
1905: 
1906:         global $config;
1907: 
1908:         if(isset($BO))
1909:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $BO);
1910:         else
1911:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), new PersonObject());
1912: 
1913:         try{
1914:             $provider->begin();
1915:         }catch (Exception $e) {
1916:             throw new AlphaException('Error beginning a new transaction, error is ['.$e->getMessage().']');
1917:         }
1918: 
1919:         self::$logger->debug('<<begin');
1920:     }
1921: 
1922:     /**
1923:      * Commits the current database transaction.
1924:      *
1925:      * @param $BO The AlphaDAO instance to pass to the database provider. Leave empty to have a new PersonObject passed.
1926:      * @since 1.0
1927:      * @throws FailedSaveException
1928:      */
1929:     public static function commit($BO = null) {
1930:         if(self::$logger == null)
1931:             self::$logger = new Logger('AlphaDAO');
1932:         self::$logger->debug('>>commit()');
1933: 
1934:         global $config;
1935: 
1936:         if(isset($BO))
1937:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $BO);
1938:         else
1939:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), new PersonObject());
1940: 
1941:         try{
1942:             $provider->commit();
1943:         }catch (Exception $e) {
1944:             throw new FailedSaveException('Error commiting a transaction, error is ['.$e->getMessage().']');
1945:         }
1946: 
1947:         self::$logger->debug('<<commit');
1948:     }
1949: 
1950:     /**
1951:      * Aborts the current database transaction.
1952:      *
1953:      * @param $BO The AlphaDAO instance to pass to the database provider. Leave empty to have a new PersonObject passed.
1954:      * @since 1.0
1955:      * @throws AlphaException
1956:      */
1957:     public static function rollback($BO = null) {
1958:         if(self::$logger == null)
1959:             self::$logger = new Logger('AlphaDAO');
1960:         self::$logger->debug('>>rollback()');
1961: 
1962:         global $config;
1963: 
1964:         if(isset($BO))
1965:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $BO);
1966:         else
1967:             $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), new PersonObject());
1968: 
1969:         try{
1970:             $provider->rollback();
1971:         }catch (Exception $e) {
1972:             throw new FailedSaveException('Error aborting a transaction, error is ['.$e->getMessage().']');
1973:         }
1974: 
1975:         self::$logger->debug('<<rollback');
1976:     }
1977: 
1978:     /**
1979:      * Static method that tries to determine if the system database has been installed or not.
1980:      *
1981:      * @return boolean
1982:      * @since 1.0
1983:      */
1984:     public static function isInstalled() {
1985:         if(self::$logger == null)
1986:             self::$logger = new Logger('AlphaDAO');
1987:         self::$logger->debug('>>isInstalled()');
1988: 
1989:         global $config;
1990: 
1991:         /*
1992:          * Install conditions are:
1993:          *
1994:          * 1. person table exists
1995:          * 2. rights table exists
1996:          */
1997:         if(AlphaDAO::checkBOTableExists('PersonObject') && AlphaDAO::checkBOTableExists('RightsObject')) {
1998:             self::$logger->debug('<<isInstalled [true]');
1999:             return true;
2000:         }else{
2001:             self::$logger->debug('<<isInstalled [false]');
2002:             return false;
2003:         }
2004:     }
2005: 
2006:     /**
2007:      * Returns true if the BO has a Relation property called tags, false otherwise.
2008:      *
2009:      * @return boolean
2010:      * @since 1.0
2011:      */
2012:     public function isTagged() {
2013:         if(isset($this->taggedAttributes) && isset($this->tags) && $this->tags instanceof Relation)
2014:             return true;
2015:         else
2016:             return false;
2017:     }
2018: 
2019:     /**
2020:      * Returns the contents of the taggedAttributes array, or an empty array if that does not exist.
2021:      *
2022:      * @return array
2023:      * @since 1.2.3
2024:      */
2025:     public function getTaggedAttributes() {
2026:         if($this->isTagged())
2027:             return $this->taggedAttributes;
2028:         else
2029:             return array();
2030:     }
2031: 
2032:     /**
2033:      * Setter for the BO version number.
2034:      *
2035:      * @param integer $versionNumber The version number.
2036:      * @since 1.0
2037:      */
2038:     private function setVersion($versionNumber) {
2039:         $this->version_num->setValue($versionNumber);
2040:     }
2041: 
2042:     /**
2043:      * Cast a BO to another type of BO.  A new BO will be returned with the same OID and
2044:      * version_num as the old BO, so this is NOT a true cast but is a copy.  All attribute
2045:      * values will be copied accross.
2046:      *
2047:      * @param string $targetClassName The name of the target BO class.
2048:      * @param AlphaDAO $originalBO The original business object.
2049:      * @return AlphaDAO The new business object resulting from the cast.
2050:      * @since 1.0
2051:      */
2052:     public function cast($targetClassName, $originalBO) {
2053:         AlphaDAO::loadClassDef($targetClassName);
2054: 
2055:         $BO = new $targetClassName;
2056:         $BO->setOID($originalBO->getOID());
2057:         $BO->setVersion($originalBO->getVersion());
2058: 
2059:         // get the class attributes
2060:         $originalBOreflection = new ReflectionClass(get_class($originalBO));
2061:         $originalBOproperties = $originalBOreflection->getProperties();
2062:         $newBOreflection = new ReflectionClass($targetClassName);
2063:         $newBOproperties = $newBOreflection->getProperties();
2064: 
2065:         // copy the property values from the old BO to the new BO
2066: 
2067:         if(count($originalBOproperties) < count($newBOproperties)) {
2068:             // the original BO is smaller, so loop over its properties
2069:             foreach($originalBOproperties as $propObj) {
2070:                 $propName = $propObj->name;
2071:                 if(!in_array($propName, $this->transientAttributes))
2072:                     $BO->set($propName, $originalBO->get($propName));
2073:             }
2074:         }else{
2075:             // the new BO is smaller, so loop over its properties
2076:             foreach($newBOproperties as $propObj) {
2077:                 $propName = $propObj->name;
2078:                 if(!in_array($propName, $this->transientAttributes))
2079:                     $BO->set($propName, $originalBO->get($propName));
2080:             }
2081:         }
2082: 
2083:         return $BO;
2084:     }
2085: 
2086:     /**
2087:      * Converts "BusinessObject" to "Business" and returns.
2088:      *
2089:      * @return string
2090:      * @since 1.0
2091:      */
2092:     public function getFriendlyClassName() {
2093:         $name = mb_substr(get_class($this), 0, -6);
2094: 
2095:         return $name;
2096:     }
2097: 
2098:     /**
2099:      * Check to see if an attribute exists on the BO.
2100:      *
2101:      * @param $attribute The attribute name.
2102:      * @return boolean
2103:      * @since 1.0
2104:      */
2105:     public function hasAttribute($attribute) {
2106:         try{
2107:             $exists = $this->$attribute;
2108:             return true;
2109:         }catch(Exception $e) {
2110:             return false;
2111:         }
2112:     }
2113: 
2114:     /**
2115:      * Stores the business object to the configured cache instance
2116:      *
2117:      * @since 1.1
2118:      */
2119:     public function addToCache() {
2120:         self::$logger->debug('>>addToCache()');
2121:         global $config;
2122: 
2123:         try {
2124:             $cache = AlphaCacheProviderFactory::getInstance($config->get('cache.provider.name'));
2125:             $cache->set(get_class($this).'-'.$this->getOID(), $this, 3600);
2126: 
2127:         }catch(Exception $e) {
2128:             self::$logger->error('Error while attempting to store a business object to the ['.$config->get('cache.provider.name').'] 
2129:                 instance: ['.$e->getMessage().']');
2130:         }
2131: 
2132:         self::$logger->debug('<<addToCache');
2133:     }
2134: 
2135:     /**
2136:      * Removes the business object from the configured cache instance
2137:      *
2138:      * @since 1.1
2139:      */
2140:     public function removeFromCache() {
2141:         self::$logger->debug('>>removeFromCache()');
2142:         global $config;
2143: 
2144:         try {
2145:             $cache = AlphaCacheProviderFactory::getInstance($config->get('cache.provider.name'));
2146:             $cache->delete(get_class($this).'-'.$this->getOID());
2147:         }catch(Exception $e) {
2148:             self::$logger->error('Error while attempting to remove a business object from ['.$config->get('cache.provider.name').']
2149:                 instance: ['.$e->getMessage().']');
2150:         }
2151: 
2152:         self::$logger->debug('<<removeFromCache');
2153:     }
2154: 
2155:     /**
2156:      * Attempts to load the business object from the configured cache instance
2157:      *
2158:      * @since 1.1
2159:      * @return boolean
2160:      */
2161:     public function loadFromCache() {
2162:         self::$logger->debug('>>loadFromCache()');
2163:         global $config;
2164: 
2165:         try {
2166:             $cache = AlphaCacheProviderFactory::getInstance($config->get('cache.provider.name'));
2167:             $BO = $cache->get(get_class($this).'-'.$this->getOID());
2168: 
2169:             if(!$BO) {
2170:                 self::$logger->debug('Cache miss on key ['.get_class($this).'-'.$this->getOID().']');
2171:                 self::$logger->debug('<<loadFromCache: [false]');
2172:                 return false;
2173:             }else{
2174:                 // get the class attributes
2175:                 $reflection = new ReflectionClass(get_class($this));
2176:                 $properties = $reflection->getProperties();
2177: 
2178:                 foreach($properties as $propObj) {
2179:                     $propName = $propObj->name;
2180: 
2181:                     // filter transient attributes
2182:                     if(!in_array($propName, $this->transientAttributes)) {
2183:                         $this->set($propName, $BO->get($propName, true));
2184:                     }elseif(!$propObj->isPrivate() && isset($this->$propName) && $this->$propName instanceof Relation) {
2185:                         $prop = $this->getPropObject($propName);
2186: 
2187:                         // handle the setting of ONE-TO-MANY relation values
2188:                         if($prop->getRelationType() == 'ONE-TO-MANY') {
2189:                             $this->set($propObj->name, $this->getOID());
2190:                         }
2191:                     }
2192:                 }
2193: 
2194:                 self::$logger->debug('<<loadFromCache: [true]');
2195:                 return true;
2196:             }
2197:         }catch(Exception $e) {
2198:             self::$logger->error('Error while attempting to load a business object from ['.$config->get('cache.provider.name').']
2199:              instance: ['.$e->getMessage().']');
2200: 
2201:             self::$logger->debug('<<loadFromCache: [false]');
2202:             return false;
2203:         }
2204:     }
2205: 
2206:     /**
2207:      * Sets the last query executed on this business object
2208:      *
2209:      * @param string $query
2210:      * @since 1.1
2211:      */
2212:     public function setLastQuery($query) {
2213:         self::$logger->sql($query);
2214:         $this->lastQuery = $query;
2215:     }
2216: 
2217:     /**
2218:      * Re-initialize the static logger property on the BO after de-serialize, as PHP does
2219:      * not serialize static properties.
2220:      *
2221:      * @since 1.2
2222:      */
2223:     public function __wakeup() {
2224:         if(self::$logger == null)
2225:             self::$logger = new Logger(get_class($this));
2226:     }
2227: 
2228:     /**
2229:      * Sets maintainHistory attribute on this DAO
2230:      *
2231:      * @param boolean $maintainHistory
2232:      * @throws IllegalArguementException
2233:      * @since 1.2
2234:      */
2235:     public function setMaintainHistory($maintainHistory) {
2236:         if(!is_bool($maintainHistory))
2237:             throw new IllegalArguementException('Non-boolean value ['.$maintainHistory.'] passed to setMaintainHistory method!');
2238: 
2239:         $this->maintainHistory = $maintainHistory;
2240:     }
2241: 
2242:     /**
2243:      * Gets the value of the  maintainHistory attribute
2244:      *
2245:      * @return boolean
2246:      * @since 1.2
2247:      */
2248:     public function getMaintainHistory() {
2249:         return $this->maintainHistory;
2250:     }
2251: 
2252:     /**
2253:      * Return a hash array of the object containing attribute names and simplfied values.
2254:      *
2255:      * @return array
2256:      * @since  1.2.4
2257:      */
2258:     public function toArray() {
2259:         // get the class attributes
2260:         $reflection = new ReflectionClass(get_class($this));
2261:         $properties = $reflection->getProperties();
2262: 
2263:         $propArray = array();
2264: 
2265:         foreach($properties as $propObj) {
2266:             $propName = $propObj->name;
2267: 
2268:             if(!in_array($propName, $this->transientAttributes)) {
2269:                 $val = $this->get($propName);
2270: 
2271:                 if (is_object($val))
2272:                     $val = $val->getValue();
2273: 
2274:                 $propArray[$propName] = $val;
2275:             }
2276:         }
2277: 
2278:         return $propArray;
2279:     }
2280: }
2281: 
2282: ?>
Alpha Framework 1.2.4 API Documentation API documentation generated by ApiGen 2.8.0