      1: <?php
      2:
      3: /**
      4:  * The RelationLookup complex data type.  Used to store object2object lookup tables for
      5:  * MANY-TO-MANY relationships between business objects
      6:  *
      7:  * @package alpha::model::types
      8:  * @since 1.0
      9:  * @author John Collins <dev@alphaframework.org>
     10:  * @version $Id: RelationLookup.inc 1693 2013-12-09 23:33:24Z alphadevx $
     11:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
     12:  * @copyright Copyright (c) 2012, John Collins (founder of Alpha Framework).
     13:  * All rights reserved.
     14:  *
     15:  * <pre>
     16:  * Redistribution and use in source and binary forms, with or
     17:  * without modification, are permitted provided that the
     18:  * following conditions are met:
     19:  *
     20:  * * Redistributions of source code must retain the above
     21:  *   copyright notice, this list of conditions and the
     22:  *   following disclaimer.
     23:  * * Redistributions in binary form must reproduce the above
     24:  *   copyright notice, this list of conditions and the
     25:  *   following disclaimer in the documentation and/or other
     26:  *   materials provided with the distribution.
     27:  * * Neither the name of the Alpha Framework nor the names
     28:  *   of its contributors may be used to endorse or promote
     29:  *   products derived from this software without specific
     30:  *   prior written permission.
     31:  *
     32:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
     33:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
     34:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     35:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     36:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     37:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     38:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     39:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     40:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     41:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     42:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     43:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     44:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     45:  * </pre>
     46:  *
     47:  */
     48: class RelationLookup extends AlphaDAO implements AlphaTypeInterface {
     49:     /**
     50:      * The OID of the left business object in the relation
     51:      *
     52:      * @var Integer
     53:      * @since 1.0
     54:      */
     55:     protected $leftID;
     56:
     57:     /**
     58:      * The OID of the right business object in the relation
     59:      *
     60:      * @var Integer
     61:      * @since 1.0
     62:      */
     63:     protected $rightID;
     64:
     65:     /**
     66:      * The name of the left business object class in the relation
     67:      *
     68:      * @var string
     69:      * @since 1.0
     70:      */
     71:     private $leftClassName;
     72:
     73:     /**
     74:      * The name of the right business object class in the relation
     75:      *
     76:      * @var string
     77:      * @since 1.0
     78:      */
     79:     private $rightClassName;
     80:
     81:     /**
     82:      * Trace logger
     83:      *
     84:      * @var Logger
     85:      * @since 1.0
     86:      */
     87:     private static $logger = null;
     88:
     89:     /**
     90:      * an array of data display labels for the class properties
     91:      *
     92:      * @var array
     93:      * @since 1.0
     94:      */
     95:     protected $dataLabels = array("OID"=>"RelationLookup ID#","leftID"=>"Left BO ID#","rightID"=>"Right BO ID#");
     96:
     97:     /**
     98:      * The message to display to the user when validation fails
     99:      *
    100:      * @var string
    101:      * @since 1.0
    102:      */
    103:     protected $helper = 'Not a valid RelationLookup value!';
    104:
    105:     /**
    106:      * The constructor
    107:      *
    108:      * @throws FailedLookupCreateException
    109:      * @throws IllegalArguementException
    110:      * @since 1.0
    111:      */
    112:     public function __construct($leftClassName, $rightClassName) {
    113:         self::$logger = new Logger('RelationLookup');
    114:         self::$logger->debug('>>__construct(leftClassName=['.$leftClassName.'], rightClassName=['. $rightClassName.'])');
    115:
    116:         // ensure to call the parent constructor
    117:         parent::__construct();
    118:
    119:         if(empty($leftClassName) || empty($rightClassName)) {
    120:             throw new IllegalArguementException('Cannot create RelationLookup object without providing the left and right class names!');
    121:         }
    122:
    123:         $this->leftClassName = $leftClassName;
    124:         $this->rightClassName = $rightClassName;
    125:
    126:         $this->leftID = new Integer();
    127:         $this->rightID = new Integer();
    128:
    129:         $this->markTransient('leftClassName');
    130:         $this->markTransient('rightClassName');
    131:         $this->markTransient('helper');
    132:         $this->markTransient('TABLE_NAME');
    133:
    134:         // add a unique composite key to these fields
    135:         $this->markUnique('leftID','rightID');
    136:
    137:         // make sure the lookup table exists
    138:         if(!$this->checkTableExists() && AlphaDAO::isInstalled()) {
    139:             // first make sure that the two BO tables exist before relating them with a lookup table
    140:             if(AlphaDAO::checkBOTableExists($leftClassName) && AlphaDAO::checkBOTableExists($rightClassName)) {
    141:                 $this->makeTable();
    142:             }else{
    143:                 throw new FailedLookupCreateException('Error trying to create a lookup table ['.$this->getTableName().'], as tables for BOs ['.$leftClassName.'] or ['.$rightClassName.'] don\'t exist!');
    144:             }
    145:         }
    146:
    147:         self::$logger->debug('<<__construct');
    148:     }
    149:
    150:     /**
    151:      * Get the leftClassName value
    152:      *
    153:      * @return string
    154:      * @since 1.0
    155:      */
    156:     public function getLeftClassName() {
    157:         return $this->leftClassName;
    158:     }
    159:
    160:     /**
    161:      * Get the rightClassName value
    162:      *
    163:      * @return string
    164:      * @since 1.0
    165:      */
    166:     public function getRightClassName() {
    167:         return $this->rightClassName;
    168:     }
    169:
    170:     /**
    171:      * Custom getter for the TABLE_NAME, which can't be static in this class due to
    172:      * the lookup tablenames being different each time.
    173:      *
    174:      * @return string
    175:      * @since 1.0
    176:      * @throws AlphaException
    177:      */
    178:     public function getTableName() {
    179:         if(isset($this->leftClassName) && isset($this->rightClassName)) {
    180:             $left = mb_substr($this->leftClassName, 0, mb_strpos($this->leftClassName, 'Object'));
    181:             $right = mb_substr($this->rightClassName, 0, mb_strpos($this->rightClassName, 'Object'));
    182:             self::$logger->debug('Setting table name to ['.$left.'2'.$right.']');
    183:             return $left.'2'.$right;
    184:         }else{
    185:             throw new AlphaException('No table name set for the class ['.get_class($this).'], left or right class name(s) missing');
    186:         }
    187:     }
    188:
    189:     /**
    190:      * This custom version provides the left/right class names to the business object constructor, required
    191:      * for RelationLookup objects.
    192:      *
    193:      * (non-PHPdoc)
    194:      * @see alpha/model/AlphaDAO::loadAllByAttribute()
    195:      */
    196:     public function loadAllByAttribute($attribute, $value, $start=0, $limit=0, $orderBy="OID", $order="ASC", $ignoreClassType=false, $constructorArgs=array()) {
    197:         if(!isset(self::$logger))
    198:             self::$logger = new Logger('RelationLookup');
    199:
    200:         self::$logger->debug('>>loadAllByAttribute(attribute=['.$attribute.'], value=['.$value.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']');
    201:
    202:         if(method_exists($this, 'before_loadAllByAttribute_callback'))
    203:             $this->before_loadAllByAttribute_callback();
    204:
    205:         global $config;
    206:
    207:         $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
    208:         $objects = $provider->loadAllByAttribute($attribute, $value, $start, $limit, $orderBy, $order, $ignoreClassType, array($this->leftClassName, $this->rightClassName));
    209:
    210:         if(method_exists($this, 'after_loadAllByAttribute_callback'))
    211:             $this->after_loadAllByAttribute_callback();
    212:
    213:         self::$logger->debug('<<loadAllByAttribute ['.count($objects).']');
    214:         return $objects;
    215:     }
    216:
    217:     /**
    218:      * Getter for the validation helper string
    219:      *
    220:      * @return string
    221:      * @since 1.0
    222:      */
    223:     public function getHelper() {
    224:         return $this->helper;
    225:     }
    226:
    227:     /**
    228:      * Set the validation helper text
    229:      *
    230:      * @param string $helper
    231:      * @since 1.0
    232:      */
    233:     public function setHelper($helper) {
    234:         $this->helper = $helper;
    235:     }
    236:
    237:     /**
    238:      * Returns an array of the OIDs of the related objects
    239:      *
    240:      * @return array
    241:      * @since 1.0
    242:      */
    243:     public function getValue() {
    244:         return array($this->leftID->getValue(), $this->rightID->getValue());
    245:     }
    246:
    247:     /**
    248:      * Used to set the OIDs of the related objects.  Pass a two-item array of OIDs, the first
    249:      * one being the left object OID, the second being the right.
    250:      *
    251:      * @param array $OIDs
    252:      * @since 1.0
    253:      * @throws IllegalArguementException
    254:      */
    255:     public function setValue($OIDs) {
    256:         try{
    257:             $this->leftID->setValue($OIDs[0]);
    258:             $this->rightID->setValue($OIDs[1]);
    259:         }catch(Exception $e) {
    260:             throw new IllegalArguementException('Array value passed to setValue is not valid ['.var_export($OIDs, true).'], array should contain two OIDs');
    261:         }
    262:     }
    263:
    264:     /**
    265:      * Used to convert the object to a printable string
    266:      *
    267:      * @return string
    268:      * @since 1.0
    269:      */
    270:     public function __toString() {
    271:         return strval($this->getTableName());
    272:     }
    273: }