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 1548 2012-07-29 17:07:07Z 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 = rtrim($this->leftClassName, "Object");
181: $right = rtrim($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: *
194: * (non-PHPdoc)
195: * @see alpha/model/AlphaDAO::loadAllByAttribute()
196: */
197: public function loadAllByAttribute($attribute, $value, $start=0, $limit=0, $orderBy="OID", $order="ASC", $ignoreClassType=false, $constructorArgs=array()) {
198: if(!isset(self::$logger))
199: self::$logger = new Logger('RelationLookup');
200:
201: self::$logger->debug('>>loadAllByAttribute(attribute=['.$attribute.'], value=['.$value.'], start=['.$start.'], limit=['.$limit.'], orderBy=['.$orderBy.'], order=['.$order.'], ignoreClassType=['.$ignoreClassType.'], constructorArgs=['.print_r($constructorArgs, true).']');
202:
203: if(method_exists($this, 'before_loadAllByAttribute_callback'))
204: $this->before_loadAllByAttribute_callback();
205:
206: global $config;
207:
208: $provider = AlphaDAOProviderFactory::getInstance($config->get('db.provider.name'), $this);
209: $objects = $provider->loadAllByAttribute($attribute, $value, $start, $limit, $orderBy, $order, $ignoreClassType, array($this->leftClassName, $this->rightClassName));
210:
211: if(method_exists($this, 'after_loadAllByAttribute_callback'))
212: $this->after_loadAllByAttribute_callback();
213:
214: self::$logger->debug('<<loadAllByAttribute ['.count($objects).']');
215: return $objects;
216: }
217:
218: /**
219: * Getter for the validation helper string
220: *
221: * @return string
222: * @since 1.0
223: */
224: public function getHelper() {
225: return $this->helper;
226: }
227:
228: /**
229: * Set the validation helper text
230: *
231: * @param string $helper
232: * @since 1.0
233: */
234: public function setHelper($helper) {
235: $this->helper = $helper;
236: }
237:
238: /**
239: * Returns an array of the OIDs of the related objects
240: *
241: * @return array
242: * @since 1.0
243: */
244: public function getValue() {
245: return array($this->leftID->getValue(), $this->rightID->getValue());
246: }
247:
248: /**
249: * Used to set the OIDs of the related objects. Pass a two-item array of OIDs, the first
250: * one being the left object OID, the second being the right.
251: *
252: * @param array $OIDs
253: * @since 1.0
254: * @throws IllegalArguementException
255: */
256: public function setValue($OIDs) {
257: try{
258: $this->leftID->setValue($OIDs[0]);
259: $this->rightID->setValue($OIDs[1]);
260: }catch(Exception $e) {
261: throw new IllegalArguementException('Array value passed to setValue is not valid ['.var_export($OIDs, true).'], array should contain two OIDs');
262: }
263: }
264:
265: /**
266: * Used to convert the object to a printable string
267: *
268: * @return string
269: * @since 1.0
270: */
271: public function __toString() {
272: return strval($this->getTableName());
273: }
274: }