Overview

Packages

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

Classes

  • AlphaType
  • Boolean
  • Date
  • DEnum
  • DEnumItem
  • Double
  • Enum
  • Integer
  • Relation
  • RelationLookup
  • Sequence
  • String
  • Text
  • Timestamp

Interfaces

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