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 1618 2012-12-19 16:51:08Z 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 = substr($this->leftClassName, 0, strpos($this->leftClassName, 'Object'));
181: $right = substr($this->rightClassName, 0, 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: }