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

Source for file Relation.inc

Documentation is available at Relation.inc

  1. <?php
  2.  
  3. require_once $config->get('sysRoot').'alpha/exceptions/AlphaException.inc';
  4. require_once $config->get('sysRoot').'alpha/model/types/AlphaType.inc';
  5. require_once $config->get('sysRoot').'alpha/model/types/AlphaTypeInterface.inc';
  6. require_once $config->get('sysRoot').'alpha/model/types/RelationLookup.inc';
  7.  
  8. /**
  9.  * The Relation complex data type
  10.  * 
  11.  * @package alpha::model::types
  12.  * @since 1.0
  13.  * @author John Collins <dev@alphaframework.org>
  14.  * @version $Id: Relation.inc 1341 2011-03-17 15:02:02Z johnc $
  15.  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  16.  * @copyright Copyright (c) 2011, John Collins (founder of Alpha Framework).
  17.  *  All rights reserved.
  18.  * 
  19.  *  <pre>
  20.  *  Redistribution and use in source and binary forms, with or
  21.  *  without modification, are permitted provided that the
  22.  *  following conditions are met:
  23.  * 
  24.  *  * Redistributions of source code must retain the above
  25.  *    copyright notice, this list of conditions and the
  26.  *    following disclaimer.
  27.  *  * Redistributions in binary form must reproduce the above
  28.  *    copyright notice, this list of conditions and the
  29.  *    following disclaimer in the documentation and/or other
  30.  *    materials provided with the distribution.
  31.  *  * Neither the name of the Alpha Framework nor the names
  32.  *    of its contributors may be used to endorse or promote
  33.  *    products derived from this software without specific
  34.  *    prior written permission.
  35.  *   
  36.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  37.  *  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  38.  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  39.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  40.  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  41.  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  42.  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  43.  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  44.  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  45.  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  46.  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  47.  *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  48.  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  49.  *  </pre>
  50.  *  
  51.  */
  52. class Relation extends AlphaType implements AlphaTypeInterface {
  53.     /**
  54.      * The name of the business object class which this class is related to
  55.      *
  56.      * @var string 
  57.      * @since 1.0
  58.      */
  59.     private $relatedClass;
  60.     
  61.     /**
  62.      * The name of the fields of the business object class by which this class is related by
  63.      *
  64.      * @var string 
  65.      * @since 1.0
  66.      */
  67.     private $relatedClassField;
  68.     
  69.     /**
  70.      * The name of the field from the related business object class which is displayed by the selection widget
  71.      *
  72.      * @var string 
  73.      * @since 1.0
  74.      */
  75.     private $relatedClassDisplayField;
  76.     
  77.     /**
  78.      * An array of fields to use the values of while rendering related display values via the selection widget
  79.      * 
  80.      * @var array 
  81.      * @since 1.0
  82.      */
  83.     private $relatedClassHeaderFields array();
  84.         
  85.     /**
  86.      * The name of the business object class on the left of a MANY-TO-MANY relation
  87.      *
  88.      * @var string 
  89.      * @since 1.0
  90.      */
  91.     private $relatedClassLeft;
  92.     
  93.     /**
  94.      * The name of the field from the related business object class on the left of a
  95.      * MANY-TO-MANY relation which is displayed by the selection widget
  96.      *
  97.      * @var string 
  98.      * @since 1.0
  99.      */
  100.     private $relatedClassLeftDisplayField;
  101.     
  102.     /**
  103.      * The name of the business object class on the right of a MANY-TO-MANY relation
  104.      *
  105.      * @var string 
  106.      * @since 1.0
  107.      */
  108.     private $relatedClassRight;
  109.     
  110.     /**
  111.      * The name of the field from the related business object class on the right of a
  112.      * MANY-TO-MANY relation which is displayed by the selection widget
  113.      *
  114.      * @var string 
  115.      * @since 1.0
  116.      */
  117.     private $relatedClassRightDisplayField;    
  118.     
  119.     /**
  120.      * The type of relation ('MANY-TO-ONE' or 'ONE-TO-MANY' or 'ONE-TO-ONE' or 'MANY-TO-MANY')
  121.      *
  122.      * @var string 
  123.      * @since 1.0
  124.      */
  125.     private $relationType;
  126.     
  127.     /**
  128.      * In the case of MANY-TO-MANY relationship, a lookup object will be required
  129.      *
  130.      * @var RelationLookup 
  131.      * @since 1.0
  132.      */
  133.     private $lookup;
  134.     
  135.     /**
  136.      * When building a relation with the TagObject BO, set this to the name of the tagged class
  137.      * 
  138.      * @var string 
  139.      * @since 1.0
  140.      */
  141.     private $taggedClass;
  142.     
  143.     /**
  144.      * An array of the allowable relationship types ('MANY-TO-ONE' or 'ONE-TO-MANY' or 'ONE-TO-ONE' or 'MANY-TO-MANY')
  145.      *
  146.      * @var array 
  147.      * @since 1.0
  148.      */
  149.     private $allowableRelationTypes array('MANY-TO-ONE','ONE-TO-MANY','ONE-TO-ONE','MANY-TO-MANY');
  150.     
  151.     /**
  152.      * The object ID (OID) value of the related object.  In the special case of a MANY-TO-MANY
  153.      * relation, contains the OID of the object on the current, accessing side.  Can contain NULL.
  154.      *
  155.      * @var mixed 
  156.      * @since 1.0
  157.      */
  158.     private $value NULL;
  159.     
  160.     /**
  161.      * The validation rule for the Relation type
  162.      * 
  163.      * @var string 
  164.      * @since 1.0
  165.      */
  166.     private $validationRule;
  167.     
  168.     /**
  169.      * The error message for the Relation type when validation fails
  170.      * 
  171.      * @var string 
  172.      * @since 1.0
  173.      */
  174.     protected $helper;
  175.     
  176.     /**
  177.      * The size of the value for the this Relation
  178.      * 
  179.      * @var integer 
  180.      * @since 1.0
  181.      */
  182.     private $size 11;
  183.     
  184.     /**
  185.      * The absolute maximum size of the value for the this Relation
  186.      * 
  187.      * @var integer 
  188.      * @since 1.0
  189.      */
  190.     const MAX_SIZE = 11;
  191.     
  192.     /**
  193.      * Constructor
  194.      * 
  195.      * @since 1.0
  196.      */
  197.     public function __construct({
  198.         $this->validationRule AlphaValidator::REQUIRED_INTEGER;        
  199.         $this->helper = ' not a valid Relation value!  A maximum of '.$this->size.' characters is allowed.';        
  200.     }
  201.     
  202.     /**
  203.      * Set the name of the business object class that this class is related to
  204.      *
  205.      * @param string $RC 
  206.      * @param string $side Only required for MANY-TO-MANY relations
  207.      * @since 1.0
  208.      * @throws IllegalArguementException
  209.      */
  210.     public function setRelatedClass($RC$side=''{        
  211.         if(in_array($RCAlphaDAO::getBOClassNames())) {
  212.             // load the class definition if it has not been loaded already
  213.             AlphaDAO::loadClassDef($RC);
  214.             switch($side{
  215.                 case '':
  216.                     $this->relatedClass $RC;
  217.                 break;
  218.                 case 'left':
  219.                     $this->relatedClassLeft $RC;
  220.                 break;
  221.                 case 'right':
  222.                     $this->relatedClassRight $RC;
  223.                 break;
  224.                 default:
  225.                     throw new IllegalArguementException('The side paramter ['.$RC.'] is not valid!');                            
  226.             }
  227.         }else{
  228.             throw new IllegalArguementException('The class ['.$RC.'] is not defined anywhere!');
  229.         }
  230.     }
  231.     
  232.     /**
  233.      * Get the name of the business object class that this class is related to
  234.      *
  235.      * @param string $RC 
  236.      * @return string 
  237.      * @since 1.0
  238.      * @throws IllegalArguementException
  239.      */
  240.     public function getRelatedClass($side=''{        
  241.         switch($side{
  242.             case '':
  243.                 return $this->relatedClass;
  244.             break;
  245.             case 'left':
  246.                 return $this->relatedClassLeft;
  247.             break;
  248.             case 'right':
  249.                 return $this->relatedClassRight;
  250.             break;
  251.             default:
  252.                 throw new IllegalArguementException('The side paramter ['.$RC.'] is not valid!');
  253.                 return '';                            
  254.         }
  255.     }
  256.     
  257.     /**
  258.      * Setter for the field of the related class
  259.      *
  260.      * @param string $RCF 
  261.      * @since 1.0
  262.      * @throws IllegalArguementException
  263.      * @throws AlphaException
  264.      */
  265.     public function setRelatedClassField($RCF{
  266.         try{
  267.             // use reflection to sure the related class has the field $RCF
  268.             $reflection new ReflectionClass($this->relatedClass);            
  269.             $properties $reflection->getProperties();            
  270.             $fieldFound false;
  271.         
  272.             foreach($properties as $propObj{                
  273.                 if($RCF == $propObj->name{
  274.                     $fieldFound true;
  275.                     break;
  276.                 }
  277.             }
  278.  
  279.             if($fieldFound)
  280.                 $this->relatedClassField $RCF;
  281.             else
  282.                 throw new IllegalArguementException('The field ['.$RCF.'] was not found in the class ['.$this->relatedClass.']');
  283.         }catch (Exception $e{
  284.             throw new AlphaException($e->getMessage());
  285.         }
  286.     }
  287.     
  288.     /**
  289.      * Getter for the field of the related class
  290.      *
  291.      * @return string 
  292.      * @since 1.0
  293.      */
  294.     public function getRelatedClassField({
  295.         return $this->relatedClassField;
  296.     }
  297.     
  298.     /**
  299.      * Setter for ONE-TO-MANY relations, which sets the header fields to
  300.      * render from the related class
  301.      * 
  302.      * @param array $fieldNames 
  303.      * @since 1.0
  304.      */
  305.     public function setRelatedClassHeaderFields($fieldNames{
  306.         $this->relatedClassHeaderFields $fieldNames;
  307.     }
  308.     
  309.     /**
  310.      * Getter for the selection widget field headings of the related class
  311.      *
  312.      * @return array 
  313.      * @since 1.0
  314.      */
  315.     public function getRelatedClassHeaderFields({
  316.         return $this->relatedClassHeaderFields;
  317.     }
  318.     
  319.     /**
  320.      * Setter for the display field from the related class
  321.      *
  322.      * @param string $RCDF 
  323.      * @param string $side Only required for MANY-TO-MANY relations
  324.      * @since 1.0
  325.      * @throws IllegalArguementException
  326.      */
  327.     public function setRelatedClassDisplayField($RCDF$side=''{
  328.         switch($side{
  329.             case '':
  330.                 $this->relatedClassDisplayField $RCDF;
  331.             break;
  332.             case 'left':
  333.                 $this->relatedClassLeftDisplayField $RCDF;
  334.             break;
  335.             case 'right':
  336.                 $this->relatedClassRightDisplayField $RCDF;
  337.             break;
  338.             default:
  339.                 throw new IllegalArguementException('The side paramter ['.$RC.'] is not valid!');                            
  340.         }
  341.     }
  342.     
  343.     /**
  344.      * Getter for the display field from the related class
  345.      *
  346.      * @param string $side Only required for MANY-TO-MANY relations
  347.      * @return string 
  348.      * @since 1.0
  349.      * @throws IllegalArguementException
  350.      */
  351.     public function getRelatedClassDisplayField($side=''{
  352.         switch($side{
  353.             case '':
  354.                 return $this->relatedClassDisplayField;
  355.             break;
  356.             case 'left':
  357.                 return $this->relatedClassLeftDisplayField;
  358.             break;
  359.             case 'right':
  360.                 return $this->relatedClassRightDisplayField;
  361.             break;
  362.             default:
  363.                 throw new IllegalArguementException('The side paramter ['.$RC.'] is not valid!');
  364.                 return '';                            
  365.         }
  366.     }
  367.     
  368.     /**
  369.      * Setter for the relation type
  370.      *
  371.      * @param string $RT 
  372.      * @throws IllegalArguementException
  373.      * @throws FailedLookupCreateException
  374.      * @throws IllegalArguementException
  375.      * @since 1.0
  376.      */
  377.     public function setRelationType($RT{
  378.         if(in_array($RT$this->allowableRelationTypes)) {
  379.             $this->relationType $RT;
  380.             if($RT == 'MANY-TO-MANY'{
  381.                 try {
  382.                     $this->lookup new RelationLookup($this->relatedClassLeft$this->relatedClassRight);
  383.                 }catch (FailedLookupCreateException $flce{
  384.                     throw $flce;
  385.                 }catch (IllegalArguementException $iae{
  386.                     throw $iae;
  387.                 }
  388.             }
  389.         }else{
  390.             throw new IllegalArguementException('Relation type of ['.$RT.'] is invalid!');
  391.         }
  392.     }
  393.     
  394.     /**
  395.      * Getter for the relation type
  396.      *
  397.      * @return string 
  398.      * @since 1.0
  399.      */
  400.     public function getRelationType({
  401.         return $this->relationType;
  402.     }
  403.     
  404.     /**
  405.      * Setter for the value (OID of related object) of this relation
  406.      *
  407.      * @param integer $val 
  408.      * @since 1.0
  409.      * @throws IllegalArguementException
  410.      */
  411.     public function setValue($val{
  412.         if(empty($val)) {
  413.             $this->value NULL;
  414.         }else{
  415.             if(!AlphaValidator::isInteger($val))
  416.                 throw new IllegalArguementException("[$val]".$this->helper);
  417.                                     
  418.             if (strlen($val<= $this->size{            
  419.                 $this->value str_pad($val11'0'STR_PAD_LEFT);                
  420.             }else{
  421.                 throw new IllegalArguementException("[$val]".$this->helper);
  422.             }
  423.         }
  424.     }
  425.     
  426.     /**
  427.      * Getter for the Relation value
  428.      *
  429.      * @return mixed 
  430.      * @since 1.0
  431.      */
  432.     public function getValue({
  433.         return $this->value;
  434.     }    
  435.     
  436.     /**
  437.       * Get the validation rule
  438.       *
  439.       * @return string 
  440.       * @since 1.0
  441.       */
  442.      public function getRule({
  443.         return $this->validationRule;
  444.     }
  445.  
  446.     /**
  447.      * Setter to override the default validation rule
  448.      *
  449.      * @param string $rule 
  450.      * @since 1.0
  451.      */
  452.     public function setRule($rule{
  453.         $this->validationRule $rule;
  454.     }
  455.     
  456.     /**
  457.      * Getter for the display value of the related class field.  In the case of a
  458.      * MANY-TO-MANY Relation, a comma-seperated sorted list of values is returned.
  459.      *
  460.      * @param string $accessingClassName Used to indicate the reading side when accessing from MANY-TO-MANY relation (leave blank for other relation types)
  461.      * @return string 
  462.      * @since 1.0
  463.      * @throws IllegalArguementException
  464.      * @throws AlphaException
  465.      */
  466.     public function getRelatedClassDisplayFieldValue($accessingClassName=''{
  467.         global $config;
  468.         
  469.         if($this->relationType == 'MANY-TO-MANY'{
  470.             /*
  471.              * 1. Use RelationLookup to get OIDs of related objects
  472.              * 2. Load related objects
  473.              * 3. Access the value of the field on the object to build the
  474.              * comma-seperated list.
  475.              */
  476.             if(empty($this->lookup))
  477.                 throw new AlphaException('Tried to load related MANY-TO-MANY fields but no RelationLookup set on the Relation object!');
  478.             
  479.             if(empty($accessingClassName))
  480.                 throw new IllegalArguementException('Tried to load related MANY-TO-MANY fields but no accessingClassName parameter set on the call to getRelatedClassDisplayFieldValue!');
  481.             
  482.             // load objects on the right from accessing on the left            
  483.             if($accessingClassName == $this->relatedClassLeft{
  484.                 AlphaDAO::loadClassDef($this->relatedClassRight);
  485.                 $obj new $this->relatedClassRight;
  486.                 
  487.                 $lookupObjects $this->lookup->loadAllByAttribute('leftID'$this->value);
  488.                 
  489.                 $values array();
  490.                 foreach($lookupObjects as $lookupObject{
  491.                     $obj->load($lookupObject->get('rightID'));
  492.                     array_push($values$obj->get($this->relatedClassRightDisplayField));
  493.                 }
  494.                 // sort array, then return as comma-seperated string
  495.                 asort($values);
  496.                 return implode(','$values);
  497.             }
  498.             // load objects on the left from accessing on the right
  499.             if($accessingClassName == $this->relatedClassRight{
  500.                 AlphaDAO::loadClassDef($this->relatedClassLeft);
  501.                 $obj new $this->relatedClassLeft;
  502.                 
  503.                 $lookupObjects $this->lookup->loadAllByAttribute('rightID'$this->value);
  504.             
  505.                 $values array();
  506.                 foreach($lookupObjects as $lookupObject{
  507.                     $obj->load($lookupObject->get('leftID'));
  508.                     array_push($values$obj->get($this->relatedClassLeftDisplayField));
  509.                 }
  510.                 // sort array, then return as comma-seperated string
  511.                 asort($values);
  512.                 return implode(','$values);
  513.             }
  514.         }else{
  515.             AlphaDAO::loadClassDef($this->relatedClass);
  516.             $obj new $this->relatedClass;
  517.             // making sure we have an object to load
  518.             if(empty($this->value|| $this->value == '00000000000'{
  519.                 return '';
  520.             }else{
  521.                 $obj->load($this->value);        
  522.                 return $obj->get($this->relatedClassDisplayField);
  523.             }
  524.         }
  525.     }
  526.     
  527.     /**
  528.      * For one-to-many and many-to-many relations, get the objects on the other side
  529.      * 
  530.      * string $accessingClassName Used to indicate the reading side when accessing from MANY-TO-MANY relation (leave blank for other relation types)
  531.      * @return array 
  532.      * @since 1.0
  533.      * @throws IllegalArguementException
  534.      * @throws AlphaException
  535.      */
  536.     public function getRelatedObjects($accessingClassName=''{
  537.         global $config;
  538.         
  539.         if($this->relationType == 'ONE-TO-MANY'{
  540.             try {
  541.                 AlphaDAO::loadClassDef($this->relatedClass);
  542.             }catch(IllegalArguementException $e{        
  543.                 throw new AlphaException('Could not load the definition for the BO class ['.$this->relatedClass.']');
  544.             }
  545.             
  546.             $obj new $this->relatedClass;
  547.             if($this->relatedClass == 'TagObject'{
  548.                 $objects $obj->loadTags($this->taggedClass$this->getValue());
  549.             }else{
  550.                 $objects $obj->loadAllByAttribute($this->getRelatedClassField()$this->getValue());
  551.             }
  552.             
  553.             return $objects;
  554.         }else// MANY-TO-MANY
  555.             if(empty($this->lookup)) {
  556.                 throw new AlphaException('Tried to load related MANY-TO-MANY objects but no RelationLookup set on the Relation object!');
  557.             }
  558.             
  559.             if(empty($accessingClassName)) {
  560.                 throw new IllegalArguementException('Tried to load related MANY-TO-MANY objects but no accessingClassName parameter set on the call to getRelatedObjects!');
  561.             }
  562.             
  563.             $objects array();
  564.             
  565.             // load objects on the right from accessing on the left            
  566.             if($accessingClassName == $this->relatedClassLeft{
  567.                 AlphaDAO::loadClassDef($this->relatedClassRight);
  568.                 
  569.                 $lookupObjects $this->lookup->loadAllByAttribute('leftID'$this->value);
  570.                 
  571.                 foreach($lookupObjects as $lookupObject{
  572.                     $obj new $this->relatedClassRight;
  573.                     $obj->load($lookupObject->get('rightID'));
  574.                     array_push($objects$obj);
  575.                 }
  576.             }
  577.             // load objects on the left from accessing on the right
  578.             if($accessingClassName == $this->relatedClassRight{
  579.                 AlphaDAO::loadClassDef($this->relatedClassLeft);
  580.                 
  581.                 $lookupObjects $this->lookup->loadAllByAttribute('rightID'$this->value);
  582.  
  583.                 foreach($lookupObjects as $lookupObject{
  584.                     $obj new $this->relatedClassLeft;
  585.                     $obj->load($lookupObject->get('leftID'));
  586.                     array_push($objects$obj);
  587.                 }                
  588.             }
  589.             
  590.             return $objects;
  591.         }
  592.     }
  593.     
  594.     /**
  595.      * For one-to-one relations, get the object on the other side
  596.      * 
  597.      * @return array 
  598.      * @since 1.0
  599.      * @throws AlphaException
  600.      */
  601.     public function getRelatedObject({
  602.         global $config;
  603.         
  604.         try {
  605.             AlphaDAO::loadClassDef($this->relatedClass);
  606.         }catch(IllegalArguementException $e{        
  607.             throw new AlphaException('Could not load the definition for the BO class ['.$this->relatedClass.']');
  608.         }
  609.         
  610.         $obj new $this->relatedClass;
  611.         $obj->loadByAttribute($this->getRelatedClassField()$this->getValue());        
  612.         
  613.         return $obj;
  614.     }
  615.     
  616.     /**
  617.      * Get the allowable size of the Relation in the database field
  618.      *    
  619.      * @return integer 
  620.      * @since 1.0
  621.      */
  622.     public function getSize({
  623.         return $this->size;
  624.     }
  625.     
  626.     /**
  627.      * Get the lookup object if available (only on MANY-TO-MANY relations, null otherwise)
  628.      * 
  629.      * @return RelationLookup 
  630.      * @since 1.0
  631.      */
  632.     public function getLookup({
  633.         return $this->lookup;
  634.     }
  635.     
  636.     /**
  637.      * Gets the side ('left' or 'right') of the passed classname on the current Relation object
  638.      *
  639.      * @param string $BOClassname 
  640.      * @return string 
  641.      * @since 1.0
  642.      * @throws IllegalArguementException
  643.      */
  644.     public function getSide($BOClassname{        
  645.         if($BOClassname == $this->relatedClassLeft
  646.             return 'left';
  647.         }elseif($BOClassname == $this->relatedClassRight{
  648.             return 'right';
  649.         }else{
  650.             throw new IllegalArguementException('Error trying to determine the MANY-TO-MANY relationship side for the classname ['.$BOClassname.']');
  651.         }
  652.     }
  653.     
  654.     /**
  655.      * Set the taggedClass property to the name of the tagged class when building relations
  656.      * to the TagObject BO.
  657.      * 
  658.      * @param $taggedClass 
  659.      * @since 1.0
  660.      */
  661.     public function setTaggedClass($taggedClass{
  662.         $this->taggedClass $taggedClass;
  663.     }
  664. }
  665.  
  666. ?>

Documentation generated on Thu, 17 Mar 2011 16:44:42 +0000 by phpDocumentor 1.4.3