]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - data/Relationships/SugarRelationship.php
Release 6.3.0beta5
[Github/sugarcrm.git] / data / Relationships / SugarRelationship.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 global $dictionary;
40 //Load all relationship metadata
41 include_once("modules/TableDictionary.php");
42 require_once("data/BeanFactory.php");
43
44
45 define('REL_LHS','LHS');
46 define('REL_RHS','RHS');
47 define('REL_BOTH','BOTH_SIDES');
48 define('REL_MANY_MANY', 'many-to-many');
49 define('REL_ONE_MANY', 'one-to-many');
50 define('REL_ONE_ONE', 'one-to-one');
51 /**
52  * A relationship is between two modules.
53  * It contains at least two links.
54  * Each link represents a connection from one record to the records linked in this relationship.
55  * Links have a context(focus) bean while relationships do not.
56  *
57  *
58  */
59 abstract class SugarRelationship
60 {
61     protected $def;
62     protected $lhsLink;
63     protected $rhsLink;
64     protected $ignore_role_filter = false;
65     protected $self_referencing = false; //A relationship is self referencing when LHS module = RHS Module
66
67     protected static $beansToResave = array();
68
69     public abstract function add($lhs, $rhs, $additionalFields = array());
70
71     /**
72      * @abstract
73      * @param  $lhs SugarBean
74      * @param  $rhs SugarBean
75      * @return void
76      */
77     public abstract function remove($lhs, $rhs);
78
79     public abstract function load($link);
80
81     /**
82      * Gets the query to load a link.
83      * This is currently public, but should prob be made protected later.
84      * @abstract
85      * @param  $link Link Object to get query for.
86      * @return void
87      */
88     public abstract function getQuery($link, $params = array());
89
90     public abstract function getJoin($link);
91
92     public abstract function relationship_exists($lhs, $rhs);
93
94     public abstract function getRelationshipTable();
95
96     /**
97      * @param  $link Link2 removes this link from the relationship.
98      * @return void
99      */
100     public function removeAll($link)
101     {
102         $focus = $link->getFocus();
103         $related = $link->getBeans();
104         foreach($related as $relBean)
105         {
106             if (empty($relBean->id)) {
107                 continue;
108             }
109
110             if ($link->getSide() == REL_LHS)
111                 $this->remove($focus, $relBean);
112             else
113                 $this->remove($relBean, $focus);
114         }
115     }
116
117     public function removeById($rowID){
118         $this->removeRow(array("id" => $rowID));
119     }
120
121     public function getRHSModule()
122     {
123         return $this->def['rhs_module'];
124     }
125
126     public function getLHSModule()
127     {
128         return $this->def['lhs_module'];
129     }
130
131     public function getLHSLink()
132     {
133         return $this->lhsLink;
134     }
135
136     public function getRHSLink()
137     {
138         return $this->rhsLink;
139     }
140
141     public function getFields()
142     {
143         return isset($this->def['fields']) ? $this->def['fields'] : array();
144     }
145
146     protected function addRow($row)
147     {
148         $existing = $this->checkExisting($row);
149         if (!empty($existing)) //Update the existing row, overriding the values with those passed in
150             return $this->updateRow($existing['id'], array_merge($existing, $row));
151
152         $values = array();
153         foreach($this->getFields() as  $def)
154         {
155             $field = $def['name'];
156             if (isset($row[$field]))
157                 $values[$field] = "'{$row[$field]}'";
158             else
159                 $values[$field] = "''";
160         }
161         $columns = implode(',', array_keys($values));
162         $values = implode(',', $values);
163         if (!empty($values))
164         {
165             $query = "INSERT INTO {$this->getRelationshipTable()} ($columns) VALUES ($values)";
166             DBManagerFactory::getInstance()->query($query);
167         }
168     }
169
170     protected function updateRow($id, $values)
171     {
172         $newVals = array();
173         //Unset the ID since we are using it to update the row
174         if (isset($values['id'])) unset($values['id']);
175         foreach($values as $field => $val)
176         {
177             $newVals[] = "$field='$val'";
178         }
179
180         $newVals = implode(",",$newVals);
181
182         $query = "UPDATE {$this->getRelationshipTable()} set $newVals WHERE id='$id'";
183
184         return DBManagerFactory::getInstance()->query($query);
185     }
186
187     protected function removeRow($where)
188     {
189         if (empty($where))
190             return false;
191
192         $date_modified = TimeDate::getInstance()->getNow()->asDb();
193         $stringSets = array();
194         foreach ($where as $field => $val)
195         {
196             $stringSets[] = "$field = '$val'";
197         }
198         $whereString = "WHERE " . implode(" AND ", $stringSets);
199
200         $query = "UPDATE {$this->getRelationshipTable()} set deleted=1 , date_modified = '$date_modified' $whereString";
201
202         return DBManagerFactory::getInstance()->query($query);
203
204     }
205
206     /**
207      * Checks for an existing row who's keys matche the one passed in.
208      * @param  $row
209      * @return array|bool returns false if now row is found, otherwise the row is returned
210      */
211     protected function checkExisting($row)
212     {
213         $leftIDName = $this->def['join_key_lhs'];
214         $rightIDName = $this->def['join_key_rhs'];
215         if (empty($row[$leftIDName]) ||  empty($row[$rightIDName]))
216             return false;
217
218         $leftID = $row[$leftIDName];
219         $rightID = $row[$rightIDName];
220         $query = "SELECT * FROM {$this->getRelationshipTable()} WHERE $leftIDName='$leftID' AND $rightIDName='$rightID' AND deleted=0";
221
222         $db = DBManagerFactory::getInstance();
223         $result = $db->query($query);
224         $row = $db->fetchByAssoc($result);
225         if (!empty($row))
226         {
227             return $row;
228         } else{
229             return false;
230         }
231     }
232
233     protected function getCustomLogicArguments($focus, $related, $link_name)
234     {
235         $custom_logic_arguments = array();
236         $custom_logic_arguments['id'] = $focus->id;
237         $custom_logic_arguments['related_id'] = $related->id;
238         $custom_logic_arguments['module'] = $focus->module_dir;
239         $custom_logic_arguments['related_module'] = $related->module_dir;
240         $custom_logic_arguments['link'] = $link_name;
241         $custom_logic_arguments['relationship'] = $this->name;
242
243         return $custom_logic_arguments;
244     }
245
246     /**
247      * @param  SugarBean $focus
248      * @param  SugarBean $related
249      * @param string $link_name
250      * @return void
251      */
252     protected function callAfterAdd($focus, $related, $link_name="")
253     {
254         $custom_logic_arguments = $this->getCustomLogicArguments($focus, $related, $link_name);
255         $focus->call_custom_logic('after_relationship_add', $custom_logic_arguments);
256     }
257
258     /**
259      * @param  SugarBean $focus
260      * @param  SugarBean $related
261      * @param string $link_name
262      * @return void
263      */
264     protected function callAfterDelete($focus, $related, $link_name="")
265     {
266         $custom_logic_arguments = $this->getCustomLogicArguments($focus, $related, $link_name);
267         $focus->call_custom_logic('after_relationship_delete', $custom_logic_arguments);
268     }
269
270     protected function add_deleted_clause($deleted=0,$add_and='',$prefix='') {
271
272                 if (!empty($prefix)) $prefix.='.';
273                 if (!empty($add_and)) $add_and=' '.$add_and.' ';
274
275                 if ($deleted==0)  return $add_and.$prefix.'deleted=0';
276                 if ($deleted==1) return $add_and.$prefix.'deleted=1';
277                 else return '';
278         }
279
280         protected function add_optional_where_clause($optional_array, $add_and='',$prefix='') {
281
282                 if (!empty($prefix)) $prefix.='.';
283                 if (!empty($add_and)) $add_and=' '.$add_and.' ';
284
285                 if(!empty($optional_array)){
286                         return $add_and.$prefix."".$optional_array['lhs_field']."".$optional_array['operator']."'".$optional_array['rhs_value']."'";
287                 }
288                 return '';
289         //end function _add_optional_where_clause
290         }
291
292     /**
293      * @param  SugarBean $bean
294      * @return void
295      */
296     public static function addToResaveList($bean)
297     {
298         if (!isset(self::$beansToResave[$bean->module_dir]))
299         {
300             self::$beansToResave[$bean->module_dir] = array();
301         }
302         self::$beansToResave[$bean->module_dir][$bean->id] = $bean;
303     }
304
305     public static function resaveRelatedBeans()
306     {
307         $GLOBALS['resavingRelatedBeans'] = true;
308
309         //Resave any bean not currently in the middle of a save operation
310         foreach(self::$beansToResave as $module => $beans)
311         {
312             foreach ($beans as $bean)
313             {
314                 if (empty($bean->deleted) && empty($bean->in_save))
315                 {
316                     $bean->save();
317                 }
318             }
319         }
320
321         $GLOBALS['resavingRelatedBeans'] = false;
322
323         //Reset the list of beans that will need to be resaved
324         self::$beansToResave = array();
325     }
326
327
328     public function isParentRelationship()
329     {
330         //Update role fields
331         if(!empty($this->def["relationship_role_column"]) && !empty($this->def["relationship_role_column_value"])
332            && $this->def["relationship_role_column"] == "parent_type" && $this->def['rhs_key'] == "parent_id")
333         {
334             return true;
335         }
336         return false;
337     }
338
339     public function __get($name)
340     {
341         if (isset($this->def[$name]))
342             return $this->def[$name];
343
344         switch($name)
345         {
346             case "relationship_type":
347                 return $this->type;
348             case 'relationship_name':
349                 return $this->name;
350             case "lhs_module":
351                 return $this->getLHSModule();
352             case "rhs_module":
353                 return $this->getRHSModule();
354             case "lhs_table" :
355                 isset($this->def['lhs_table']) ? $this->def['lhs_table'] : "";
356             case "rhs_table" :
357                 isset($this->def['rhs_table']) ? $this->def['rhs_table'] : "";
358             case "list_fields":
359                 return array('lhs_table', 'lhs_key', 'rhs_module', 'rhs_table', 'rhs_key', 'relationship_type');
360         }
361
362         if (isset($this->$name))
363             return $this->$name;
364
365         return null;
366     }
367 }