Alpha Framework alpha--model
[ class tree: alpha--model ] [ index: alpha--model ] [ all elements ]

Source for file AlphaDAO.inc

Documentation is available at AlphaDAO.inc

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

Documentation generated on Tue, 13 Dec 2011 20:25:46 +0000 by phpDocumentor 1.4.3