Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

data/Link.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2 1
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-2013 SugarCRM Inc.
6
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
8
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 ********************************************************************************/
40
41
/*********************************************************************************
42
43
* Description:  Defines the base class for new data type, Relationship, methods in the class will
44
* be used to manipulate relationship between object instances.
45
* Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
46
* All Rights Reserved.
47
* Contributor(s): ______________________________________..
48
********************************************************************************/
49
50
51
class Link {
52
53
	/* Private variables.*/
54
	var $_log;
55
	var $_relationship_name; //relationship this attribute is tied to.
56
	var $_bean; //stores a copy of the bean.
57
	var $_relationship= '';
58
	var $_bean_table_name;
59
	var $_bean_key_name='id';
60
	private $relationship_fields = array();
61
	var $_db;
62
	var $_swap_sides = false;
63
	var $_rhs_key_override = false;
64
	var $_bean_filter_field = '';
65
66
	//if set to true role column will not be added to the filter criteria.
67
	var $ignore_role_filter=false;
68
	//if set to true distinct clause will be added to the select list.
69
	var $add_distinct=false;
70
	//value of this variable dictates the action to be taken when a duplicate relationship record is found.
71
	//1-ignore,2-update,3-delete.
72
	//var $when_dup_relationship_found=2; // deprecated - only used by Queues, which is also no longer used
73
74
	// a value for duplicate variable is stored by the _relatinship_exists method.
75
	var $_duplicate_key;
76
	var $_duplicate_where;
77
78
	/* Parameters:
79
	 * 		$_rel_name: use this relationship key.
80
	 * 		$_bean: reference of the bean that instantiated this class.
81
	 * 		$_fieldDef: vardef entry for the field.
82
	 * 		$_table_name: optional, fetch from the bean's table name property.
83
	 * 		$_key_name: optional, name of the primary key column for _table_name
84
	 */
85
	function __construct($_rel_name, &$_bean, $fieldDef, $_table_name='', $_key_name=''){
86
		global $dictionary;
87
        require_once("modules/TableDictionary.php");
88
        $GLOBALS['log']->debug("Link Constructor, relationship name: ".$_rel_name);
89
		$GLOBALS['log']->debug("Link Constructor, Table name: ".$_table_name);
90
		$GLOBALS['log']->debug("Link Constructor, Key name: ".$_key_name);
91
92
        $this->_relationship_name=$_rel_name;
93
		$this->relationship_fields = (!empty($fieldDef['rel_fields']))?$fieldDef['rel_fields']: array();
94
		$this->_bean=&$_bean;
95
		$this->_relationship=new Relationship();
96
		//$this->_relationship->retrieve_by_string_fields(array('relationship_name'=>$this->_relationship_name));
97
		$this->_relationship->retrieve_by_name($this->_relationship_name);
98
99
		$this->_db = DBManagerFactory::getInstance();
100
101
102
		//Following behavior is tied to a property(ignore_role) value in the vardef. It alters the values of 2 properties, ignore_role_filter and add_distinct.
103
		//the property values can be altered again before any requests are made.
104
		if (!empty($fieldDef) && is_array($fieldDef)) {
105
			if (array_key_exists('ignore_role', $fieldDef)) {
106
				if ($fieldDef['ignore_role'] == true) {
107
					$this->ignore_role_filter=true;
108
					$this->add_distinct=true;
109
				}
110
			}
111
		}
112
113
		$this->_bean_table_name=(!empty($_table_name)) ? $_table_name : $_bean->table_name;
114
		if (!empty($key_name)) {
0 ignored issues
show
The variable $key_name does not exist. Did you mean $_key_name?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
115
			$this->_bean_key_name=$_key_name;
116
		} else {
117
118
			if ($this->_relationship->lhs_table != $this->_relationship->rhs_table) {
119
120
				if ($_bean->table_name == $this->_relationship->lhs_table)
121
					$this->_bean_key_name=$this->_relationship->lhs_key;
122
123
				if ($_bean->table_name == $this->_relationship->rhs_table)
124
					$this->_bean_key_name=$this->_relationship->rhs_key;
125
126
			}
127
		}
128
129
		if ($this->_relationship->lhs_table == $this->_relationship->rhs_table && isset($fieldDef['side']) && $fieldDef['side'] == 'right'){
130
		    $this->_swap_sides = true;
131
		}
132
133
		if (!empty($fieldDef['rhs_key_override'])) {
134
			$this->_rhs_key_override = true;
135
		}
136
		if (!empty($fieldDef['bean_filter_field'])) {
137
			$this->_bean_filter_field = $fieldDef['bean_filter_field'];
138
		}
139
140
		//default to id if not set.
141
		if (empty($this->_bean_key_name))$this->_bean_key_name='id';
142
143
		$GLOBALS['log']->debug("Link Constructor, _bean_table_name: ".$this->_bean_table_name);
144
		$GLOBALS['log']->debug("Link Constructor, _bean_key_name: ".$this->_bean_key_name);
145
		if (!empty($this->_relationship->id)) $GLOBALS['log']->debug("Link Constructor, relationship record found.");
146
		else $GLOBALS['log']->debug("Link Constructor, No relationship record.") ;
147
148
	}
149
150
    function loadedSuccesfully() {
151
        return !empty($this->_relationship->id);
152
    }
153
154
	/* This method will return the following based on cardinality of the relationship.
155
	 *  # one-to-many, many-to-many: empty array if not data is found else array of keys.
156
	 *  # if many-to-many and $role set to true : empty array if not data is found else
157
	 *  array of array which contain id+other fields.
158
	 *  # many-to-one, one-to-one: null if no linked data is found, else key value.
159
	 *
160
	 * For a self referencing relationship the function will behave as if the user is trying
161
	 * to access the child records. To get to the parent records use the getParent() method.
162
	 */
163
    function get($role = false) {
164
        if($role){
165
            $role_field = $this->_get_link_table_role_field($this->_relationship_name);
166
            if($role_field !== false){
167
                $query = $this->getQuery(false, array(),0, "", false, "", $role_field);
168
            }else{
169
                return array();
170
            }
171
        }else{
172
            $query = $this->getQuery();
173
        }
174
        $result = $this->_db->query($query, true);
175
        $list = Array();
176
        while($row = $this->_db->fetchByAssoc($result))
177
        {
178
            if($role){
179
                $list[] = $row;
180
            }else{
181
                $list[] = $row['id'];
182
            }
183
        }
184
        return $list;
185
    }
186
187
	function getRelatedTableName() {
188
189
		$bean_is_lhs=$this->_get_bean_position();
190
		if (!isset($bean_is_lhs)) {
191
			$GLOBALS['log']->debug("Invalid relationship parameters. Exiting..");
192
			return null;
193
		}
194
195
		if ($bean_is_lhs) {
196
			return $this->_relationship->rhs_table;
197
		} else {
198
			return $this->_relationship->lhs_table;
199
		}
200
	}
201
202
	function getRelatedModuleName() {
203
204
		$bean_is_lhs=$this->_get_bean_position();
205
		if (!isset($bean_is_lhs)) {
206
			$GLOBALS['log']->debug("Invalid relationship parameters. Exiting..");
207
			return null;
208
		}
209
210
		if ($bean_is_lhs) {
211
			return $this->_relationship->rhs_module;
212
		} else {
213
			return $this->_relationship->lhs_module;
214
		}
215
	}
216
217
218
	function getRelatedFields(){
219
		return $this->relationship_fields;
220
	}
221
222
	function getRelatedField($name){
223
		return (!empty($this->relationship_fields[$name]))? $this->relationship_fields[$name]: null;
224
	}
225
226
	function getRelationshipObject() {
227
	   return $this->_relationship;
228
	}
229
230
	function _get_bean_position() {
231
		//current beans module and table are on the left side or the right side.
232
		$position = false;
233
		if ($this->_relationship->lhs_table == $this->_bean_table_name &&  $this->_relationship->lhs_key == $this->_bean_key_name) {
234
			$position =  true;
235
236
		}
237
		if ($this->_relationship->rhs_table == $this->_bean_table_name &&  $this->_relationship->rhs_key == $this->_bean_key_name) {
238
			$position =  false;
239
		}
240
241
		if($this->_swap_sides){
242
			return 	!$position;
243
		}
244
		return $position;
245
	}
246
247
	function _is_self_relationship() {
248
		if ($this->_relationship->lhs_table == $this->_relationship->rhs_table) {
249
			return true;
250
		}
251
		return false;
252
	}
253
254
	function getJoin($params, $return_array =false)
255
	{
256
		$join_type= ' INNER JOIN ';
257
			if(isset($params['join_type'])){
258
					$join_type = $params['join_type'];
259
			}
260
		$id = -1;
261
		$join = '';
262
		$bean_is_lhs=$this->_get_bean_position();
263
264
		if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type=='many-to-one' or
265
   			($this->_relationship->relationship_type=='one-to-many' && !$bean_is_lhs))
266
		{
267
			if ($bean_is_lhs) {
268
			    $table = $this->_relationship->rhs_table;
269
			    $key = $this->_relationship->rhs_key;
270
                // check right table alias
271
			    $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']);
272
			    $other_key = $this->_relationship->lhs_key;
273
			} else {
274
			    $key = $this->_relationship->lhs_key;
275
			    $table = $this->_relationship->lhs_table;
276
277
				if ( ! empty($params['join_table_alias']))
278
				{
279
			    	$table_with_alias = $table. " ".$params['join_table_alias'];
280
			    	$table = $params['join_table_alias'];
281
				}
282
			    $other_table = (empty($params['right_join_table_alias']) ? $this->_relationship->rhs_table : $params['right_join_table_alias']);
283
			    $other_key = $this->_relationship->rhs_key;
284
			}
285
286
		    $join = $join_type . ' '. $table_with_alias . " ON\n".$table.'.'.$key.'= '.$other_table.'.'.$other_key ." AND ". $table.".deleted=0\n";
287
288
		}
289
		if ($this->_relationship->relationship_type == 'one-to-many' && $bean_is_lhs) {
290
291
			    $table = $this->_relationship->rhs_table;
292
			    $key = $this->_relationship->rhs_key;
293
			    $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']);
294
			    $other_key = $this->_relationship->lhs_key;
295
					if ( ! empty($params['join_table_alias']))
296
					{
297
			    	$table_with_alias = $table. " ".$params['join_table_alias'];
298
			    	$table = $params['join_table_alias'];
299
					}
300
301
			    $join = $join_type . ' '.$table_with_alias . " ON\n".$table.'.'.$key.'= '.$other_table.'.'.$other_key ." AND ". $table.".deleted=0\n";
302
303
		}
304
305
		if ($this->_relationship->relationship_type=='many-to-many' )
306
		{
307
			if ( ! empty($params['join_table_alias']))
308
			{
309
		   		$table_with_alias = $this->_relationship->join_table. " ".$params['join_table_alias'];
310
		   		$table = $params['join_table_alias'];
311
				$rel_table_with_alias =
312
					$this->_relationship->join_table. " ".
313
					$params['join_table_link_alias'];
314
				$rel_table = $params['join_table_link_alias'];
315
			}
316
317
			if ( $bean_is_lhs )
318
			{
319
                $other_table = (empty($params['left_join_table_alias']) ? $this->_relationship->lhs_table : $params['left_join_table_alias']);
320
				$join .= $join_type . ' '.$rel_table_with_alias.' ON '.$other_table.".".$this->_relationship->lhs_key."=".$rel_table.".".$this->_relationship->join_key_lhs."  AND ".$rel_table.".deleted=0\n";
321
			} else
322
			{
323
                $other_table = (empty($params['right_join_table_alias']) ? $this->_relationship->rhs_table : $params['right_join_table_alias']);
324
				$join .= $join_type . ' '.$rel_table_with_alias.' ON '.$other_table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs."  AND ".$rel_table.".deleted=0\n";
325
			}
326
			if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter)
327
			{
328
				$join.=" AND ".$rel_table.'.'.$this->_relationship->relationship_role_column;
329
				//role column value.
330
				if (empty($this->_relationship->relationship_role_column_value))
331
				{
332
					$join.=' IS NULL';
333
				} else {
334
					$join.= "='".$this->_relationship->relationship_role_column_value."'";
335
				}
336
				$join.= "\n";
337
			}
338
			if ( ! empty($params['join_table_alias']))
339
			{
340
				if ( $bean_is_lhs )
341
				{
342
			  	  $table_with_alias = $this->_relationship->rhs_table. " ".$params['join_table_alias'];
343
				} else {
344
			  	  $table_with_alias = $this->_relationship->lhs_table. " ".$params['join_table_alias'];
345
				}
346
			   	$table = $params['join_table_alias'];
347
			}
348
349
			if ( $bean_is_lhs )
350
			{
351
				if($this->_rhs_key_override){
352
					$join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs." AND ".$table.".deleted=0";
353
				}else{
354
              	 	$join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->lhs_key."=".$rel_table.".".$this->_relationship->join_key_rhs." AND ".$table.".deleted=0";
355
				}
356
			} else {
357
                $join .= $join_type . ' '.$table_with_alias.' ON '.$table.".".$this->_relationship->rhs_key."=".$rel_table.".".$this->_relationship->join_key_lhs." AND ".$table.".deleted=0";
358
			}
359
                $join.= "\n";
360
		}
361
362
		if($return_array){
363
			$ret_arr = array();
364
			$ret_arr['join'] = $join;
365
			$ret_arr['type'] = $this->_relationship->relationship_type;
366
			if ( $bean_is_lhs ){
367
368
				$ret_arr['rel_key'] = 	$this->_relationship->join_key_rhs;
369
			}else{
370
371
				$ret_arr['rel_key'] = 	$this->_relationship->join_key_lhs;
372
			}
373
			return $ret_arr;
374
		}
375
		return $join;
376
	}
377
378
379
	function _add_deleted_clause($deleted=0,$add_and='',$prefix='') {
380
381
		if (!empty($prefix)) $prefix.='.';
382
		if (!empty($add_and)) $add_and=' '.$add_and.' ';
383
384
		if ($deleted==0)  return $add_and.$prefix.'deleted=0';
385
		if ($deleted==1) return $add_and.$prefix.'deleted=1';
386
		else return '';
387
	}
388
389
	function _add_optional_where_clause($optional_array, $add_and='',$prefix='') {
390
391
		if (!empty($prefix)) $prefix.='.';
392
		if (!empty($add_and)) $add_and=' '.$add_and.' ';
393
394
		if(!empty($optional_array)){
395
			return $add_and.$prefix."".$optional_array['lhs_field']."".$optional_array['operator']."'".$optional_array['rhs_value']."'";
396
		}
397
		return '';
398
	//end function _add_optional_where_clause
399
	}
400
401
402
403
	function getQuery($return_as_array=false, $sort_array = array(),$deleted=0, $optional_where="", $return_join = false, $bean_filter="", $role="", $for_subpanels = false){
404
405
		$select='';
406
		$from='';
407
		$join = '';
408
		$where='';
409
		$join_tables = array();
410
		$bean_is_lhs=$this->_get_bean_position();
411
412
		if (!isset($bean_is_lhs)) {
413
			$GLOBALS['log']->debug("Invalid relationship parameters. Exiting..");
414
			return null;
415
		}
416
417
		if (empty($bean_filter)) {
418
			if(!empty($this->_bean_filter_field)){
419
				$bean_filter_field = $this->_bean_filter_field;
420
				$bean_filter="= '".$this->_bean->$bean_filter_field."'";
421
			}else{
422
				$bean_filter="= '".$this->_bean->id."'";
423
			}
424
		}
425
426
		$GLOBALS['log']->debug("getQuery, Bean is LHS: ".$bean_is_lhs);
427
		$GLOBALS['log']->debug("getQuery, Relationship type=".$this->_relationship->relationship_type);
428
		$GLOBALS['log']->debug("getQuery, Relationship role column name=".$this->_relationship->relationship_role_column);
429
430
		if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type=='many-to-one' or
431
		     ($this->_relationship->relationship_type=='one-to-many' && !$bean_is_lhs)) {
432
433
			$GLOBALS['log']->debug("Processing one-to-one,many-to-one,one-to-many.");
434
435
			if ($this->add_distinct) {
436
				$select='SELECT DISTINCT id';
437
			} else {
438
				$select='SELECT id';
439
			}
440
441
			if ($bean_is_lhs) {
442
			    $from= 'FROM '.$this->_relationship->rhs_table;
443
			    $where='WHERE '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key.$bean_filter;
444
			    if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) {
445
			    	$where.=" AND ".$this->_relationship->rhs_table.'.'.$this->_relationship->relationship_role_column;
446
447
			    	//role column value.
448
			    	if (empty($this->_relationship->relationship_role_column_value)) {
449
			    		$where.=' IS NULL';
450
			    	} else {
451
			    		$where.= "='".$this->_relationship->relationship_role_column_value."'";
452
			    	}
453
			    }
454
455
			    //add deleted clause - but not if we're dealing with a Custom table which will lack the 'deleted' field
456
                if(substr_count($this->_relationship->rhs_table, '_cstm') == 0)
457
			     $where.=$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table );
458
459
				if($optional_where!=""){
460
				//process optional where
461
					$where.=$this->_add_optional_where_clause($optional_where,'AND');
462
				}
463
464
465
			}
466
			else {
467
			    $from= 'FROM '.$this->_relationship->lhs_table;
468
			    $where='WHERE '.$this->_relationship->lhs_table.'.'.$this->_relationship->lhs_key."= '".$this->_bean->{$this->_relationship->rhs_key}."'";
469
			    //added deleted clause.
470
			    $where.=$this->_add_deleted_clause($deleted,'AND', $this->_relationship->lhs_table);
471
472
473
				if($optional_where!=""){
474
				//process optional where
475
					$where.=$this->_add_optional_where_clause($optional_where,'AND');
476
				}
477
478
			}
479
		}
480
		if ($this->_relationship->relationship_type == 'one-to-many' && $bean_is_lhs) {
481
482
			$GLOBALS['log']->debug("Processing one-to-many.");
483
484
			if ($this->add_distinct) {
485
				$select='SELECT DISTINCT '.$this->_relationship->rhs_table.'.id';
486
			} else {
487
				$select='SELECT '.$this->_relationship->rhs_table.'.id';
488
			}
489
			$from= 'FROM '.$this->_relationship->rhs_table;
490
		    $where='WHERE '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key.$bean_filter;
491
		    if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) {
492
		    	$where.=" AND ".$this->_relationship->rhs_table.'.'.$this->_relationship->relationship_role_column;
493
		    	//role column value.
494
		    	if (empty($this->_relationship->relationship_role_column_value)) {
495
		    		$where.=' IS NULL';
496
		    	} else {
497
		    		$where.= "='".$this->_relationship->relationship_role_column_value."'";
498
		    	}
499
		    }
500
501
            //add deleted clause - but not if we're dealing with a Custom table which will lack the 'deleted' field
502
            if(substr_count($this->_relationship->rhs_table, '_cstm') == 0)
503
		        $where.=$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table);
504
505
			if($optional_where!=""){
506
			//process optional where
507
				$where.=$this->_add_optional_where_clause($optional_where,'AND');
508
			}
509
510
		}
511
512
		if ($this->_relationship->relationship_type=='many-to-many' ) {
513
			$GLOBALS['log']->debug("Processing many-to-many.");
514
515
			$swap = !$for_subpanels && $this->_swap_sides;
516
			if (($bean_is_lhs && !$swap) || (!$bean_is_lhs && $swap)) {
517
				if ($this->add_distinct) {
518
					$select="SELECT DISTINCT ".$this->_relationship->rhs_table.".id";
519
				} else {
520
					$select="SELECT ".$this->_relationship->rhs_table.".id";
521
				}
522
523
			    $from= 'FROM '.$this->_relationship->rhs_table;
524
			    $subjoin=' INNER JOIN '.$this->_relationship->join_table.' ON ('.$this->_relationship->rhs_table.".".$this->_relationship->rhs_key."=".$this->_relationship->join_table.".".$this->_relationship->join_key_rhs." AND ".$this->_relationship->join_table.".".$this->_relationship->join_key_lhs.$bean_filter;
525
				$join_tables[] = $this->_relationship->join_table;
526
			    if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) {
527
			    	$subjoin.=" AND ".$this->_relationship->join_table.'.'.$this->_relationship->relationship_role_column;
528
529
			    	//role column value.
530
			    	if (empty($this->_relationship->relationship_role_column_value)) {
531
			    		$subjoin.=' IS NULL';
532
			    	} else {
533
			    		$subjoin.= "='".$this->_relationship->relationship_role_column_value."'";
534
			    	}
535
			    }
536
			    $subjoin.=')';
537
			   $join .= $subjoin;
538
			    $from .= $subjoin;
539
540
541
				//add deleted clause.
542
				if ($deleted == 0 or $deleted==1) {
543
			    	$where.=' WHERE '.$this->_add_deleted_clause($deleted,'',$this->_relationship->join_table).$this->_add_deleted_clause($deleted,'AND',$this->_relationship->rhs_table);
544
				}
545
546
547
				if($optional_where!=""){
548
				//process optional where
549
					$where.=$this->_add_optional_where_clause($optional_where,'AND', $this->_relationship->rhs_table);
550
				}
551
552
553
			}
554
			else {
555
				if ($this->add_distinct) {
556
					$select="SELECT DISTINCT ".$this->_relationship->lhs_table.".id";
557
				} else {
558
					$select="SELECT ".$this->_relationship->lhs_table.".id";
559
				}
560
561
			    $from= 'FROM '.$this->_relationship->lhs_table;
562
			    $subjoin=' INNER JOIN '.$this->_relationship->join_table.' ON ('.$this->_relationship->lhs_table.".".$this->_relationship->lhs_key."=".$this->_relationship->join_table.".".$this->_relationship->join_key_lhs." AND ".$this->_relationship->join_table.".".$this->_relationship->join_key_rhs.$bean_filter;
563
			    $join_tables[] = $this->_relationship->join_table;
564
			    if (!empty($this->_relationship->relationship_role_column) && !$this->ignore_role_filter) {
565
			    	$subjoin.=" AND ".$this->_relationship->relationship_role_column;
566
567
			    	//role column value.
568
			    	if (empty($this->_relationship->relationship_role_column_value)) {
569
			    		$subjoin.=' IS NULL';
570
			    	} else {
571
			    		$subjoin.= "='".$this->_relationship->relationship_role_column_value."'";
572
			    	}
573
			    }
574
				$subjoin.=')';
575
				$join .= $subjoin;
576
			    $from .= $subjoin;
577
				//add deleted clause.
578
				if ($deleted == 0 or $deleted==1) {
579
			    	$where.=' WHERE '.$this->_add_deleted_clause($deleted,'',$this->_relationship->join_table).$this->_add_deleted_clause($deleted,'AND',$this->_relationship->lhs_table);
580
				}
581
582
583
				if($optional_where!=""){
584
				//process optional where
585
					$where.=$this->_add_optional_where_clause($optional_where,'AND', $this->_relationship->lhs_table);
586
				}
587
588
			}
589
		    if (!empty($role)){
590
                $select.=", ".$this->_relationship->join_table.".".$role;
591
            }
592
		}
593
		if ($return_as_array) {
594
			$query_as_array['select']=$select;
595
			$query_as_array['from']=$from;
596
			$query_as_array['where']=$where;
597
			if($return_join){
598
					$query_as_array['join'] = $join;
599
					$query_as_array['join_tables'] = $join_tables;
600
			}
601
			return $query_as_array;
602
		}
603
		else {
604
			$query = $select.' '.$from.' '.$where;
605
			$GLOBALS['log']->debug("Link Query=".$query);
606
			return $query;
607
		}
608
	}
609
610
	function getBeans($template, $sort_array = array(), $begin_index = 0, $end_index = -1, $deleted=0, $optional_where="") {
611
		$query = $this->getQuery(false,array(), $deleted, $optional_where); //get array of IDs
612
		return $this->_bean->build_related_list($query, $template);
613
	}
614
615
	function _add_one_to_many_table_based($key,$bean_is_lhs) {
616
617
		if ($bean_is_lhs) {
618
			$set_key_value=$this->_bean->id;
619
			$where_key_value=$key;
620
		}
621
		else {
622
			$set_key_value=$key;
623
			$where_key_value=$this->_bean->id;
624
		}
625
626
		$query= 'UPDATE '.$this->_relationship->rhs_table;
627
		$query.=' SET '.$this->_relationship->rhs_table.'.'.$this->_relationship->rhs_key."='".$set_key_value."'";
628
629
		//add role column to the query.
630
		if (!empty($this->_relationship->relationship_role_column)) {
631
			$query.=' ,'.$this->_relationship->relationship_role_column."='".$this->_relationship->relationship_role_column_value."'";
632
		}
633
		$query.=' WHERE '.$this->_relationship->rhs_table.".id='".$where_key_value."'";
634
635
		$GLOBALS['log']->fatal("Relationship Query ".$query);
636
637
		$result=$this->_db->query($query, true);
638
	}
639
640
	/* handles many to one*/
641
	function _add_many_to_one_bean_based($key) {
642
643
		//make a copy of this bean to avoid recursion.
644
		$bean=new $this->_bean->object_name;
645
		$bean->retrieve($this->_bean->id);
646
647
	   	$bean->{$this->_relationship->lhs_key}=$key;
648
649
	   	//set relationship role.
650
	   	if (!empty($this->_relationship->relationship_role_column)) {
651
	   		$bean->{$this->_relationship->relationship_role_column}=$this->_relationship->relationship_role_column_value;
652
	   	}
653
	   	$GLOBALS['log']->fatal("Adding many to one bean based {$bean->module_dir} {$bean->id}");
654
	   	$bean->save();
655
	}
656
657
658
	/* use this function to create link between 2 objects
659
	 * 1:1 will be treated like 1 to many.
660
	 * todo handle self referencing relationships
661
	 * the function also allows for setting of values for additional field in the table being
662
	 * updated to save the relationship, in case of many-to-many relationships this would be the join table.
663
	 * the values should be passed as key value pairs with column name as the key name and column value as key value.
664
	 */
665
	function add($rel_keys,$additional_values=array()) {
666
667
		if (!isset($rel_keys) or empty($rel_keys)) {
668
			$GLOBALS['log']->fatal("Link.add, Null key passed, no-op, returning... ");
669
			return;
670
		}
671
672
		//check to ensure that we do in fact have an id on the bean.
673
		if(empty($this->_bean->id)){
674
			$GLOBALS['log']->fatal("Link.add, No id on the bean... ");
675
			return;
676
		}
677
678
		if (!is_array($rel_keys)) {
679
			$keys[]=$rel_keys;
680
		} else {
681
			$keys=$rel_keys;
682
		}
683
684
		$bean_is_lhs=$this->_get_bean_position();
685
		if (!isset($bean_is_lhs)) {
686
			$GLOBALS['log']->fatal("Invalid relationship parameters. Exiting..");
687
			return null;
688
		}
689
		//if multiple keys are passed then check for unsupported relationship types.
690
		if (count($keys) > 1) {
691
			if (($this->_relationship->relationship_type == 'one-to-one')
692
				or ($this->_relationship->relationship_type == 'one-to-many' and !$bean_is_lhs)
693
				or ($this->_relationship->relationship_type == 'many-to-one')) {
694
					$GLOBALS['log']->fatal("Invalid parameters passed to function, the relationship does not support addition of multiple records.");
695
					return;
696
				}
697
		}
698
        $GLOBALS['log']->debug("Relationship type = {$this->_relationship->relationship_type}");
699
        foreach($keys as $key) {
700
701
			//fetch the related record using the key and update.
702
			if ($this->_relationship->relationship_type=='one-to-one' || $this->_relationship->relationship_type == 'one-to-many' ) {
703
                $this->_add_one_to_many_table_based($key,$bean_is_lhs);
704
			}
705
706
			//updates the bean passed to the instance....
707
			//todo remove this case.
708
			if ($this->_relationship->relationship_type=='many-to-one') {
709
				$this->_add_many_to_one_bean_based($key);
710
		    }
711
712
		    //insert record in the link table.
713
			if ($this->_relationship->relationship_type=='many-to-many' ) {
714
                //replace existing relationships for one-to-one
715
                if(!empty($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type']) &&
716
					($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type'] == 'one-to-one'))
717
                {
718
                    //Remove all existing links with either bean.
719
                    $old_rev = isset($this->_relationship->reverse) ? false : $this->_relationship->reverse;
720
                    $this->_relationship->reverse = true;
721
                    $this->delete($key);
722
                    $this->delete($this->_bean->id);
723
                    $this->_relationship->reverse = $old_rev;
724
                }
725
726
				//Swap the bean positions for self relationships not coming from subpanels.
727
				//such as one-to-many relationship fields generated in studio/MB
728
				$swap = !isset($_REQUEST['subpanel_id']) && $this->_swap_sides;
729
				//add keys from the 2 tables to the additional keys array..
730
				if (($bean_is_lhs && !$swap) || (!$bean_is_lhs && $swap)) {
731
					$additional_values[$this->_relationship->join_key_lhs]=$this->_bean->id;
732
					$additional_values[$this->_relationship->join_key_rhs]=$key;
733
				} else {
734
					$additional_values[$this->_relationship->join_key_rhs]=$this->_bean->id;
735
					$additional_values[$this->_relationship->join_key_lhs]=$key;
736
				}
737
				//add the role condition.
738
				if (!empty($this->_relationship->relationship_role_column) && !empty($this->_relationship->relationship_role_column_value)) {
739
					$additional_values[$this->_relationship->relationship_role_column]=$this->_relationship->relationship_role_column_value;
740
				}
741
				//add deleted condition.
742
				$additional_values['deleted']=0;
743
744
				$this->_add_many_to_many($additional_values);
745
746
				//reverse will be set to true only for self-referencing many-to-many relationships.
747
				if ($this->_is_self_relationship() && !empty($GLOBALS['dictionary'][$this->_relationship_name]) &&
748
					!empty($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type']) &&
749
					$GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type'] == 'many-to-many' ||
750
				(!empty($this->_relationship->reverse) && $this->_relationship->reverse == true )){
751
					//swap key values;
752
					$temp=$additional_values[$this->_relationship->join_key_lhs];
753
					$additional_values[$this->_relationship->join_key_lhs]=$additional_values[$this->_relationship->join_key_rhs];
754
					$additional_values[$this->_relationship->join_key_rhs]=$temp;
755
756
					$this->_add_many_to_many($additional_values);
757
				}
758
			}
759
            $custom_logic_arguments = array();
760
            $custom_reverse_arguments = array();
761
            $custom_logic_arguments['related_id'] = $key;
762
            $custom_logic_arguments['id'] =  $this->_bean->id;
763
            $custom_reverse_arguments['related_id'] = $this->_bean->id;
764
            $custom_reverse_arguments['id'] = $key;
765
            if($bean_is_lhs) {
766
                $custom_logic_arguments['module'] = $this->_relationship->lhs_module;
767
                $custom_logic_arguments['related_module'] = $this->_relationship->rhs_module;
768
                $custom_reverse_arguments['module'] = $this->_relationship->rhs_module;
769
                $custom_reverse_arguments['related_module'] = $this->_relationship->lhs_module;
770
            } else {
771
                $custom_logic_arguments['related_module'] = $this->_relationship->lhs_module;
772
                $custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module;
773
                $custom_logic_arguments['module'] = $this->_relationship->rhs_module;
774
                $custom_reverse_arguments['module'] = $this->_relationship->lhs_module;
775
            }
776
            /**** CALL IT FROM THE MAIN BEAN FIRST ********/
777
            $this->_bean->call_custom_logic('after_relationship_add', $custom_logic_arguments);
778
            /**** NOW WE HAVE TO CALL THE LOGIC HOOK THE OTHER WAY SINCE IT TAKES TWO FOR A RELATIONSHIP****/
779
            global $beanList;
780
            if ( isset($beanList[$custom_logic_arguments['related_module']]) ) {
781
                $class = $beanList[$custom_logic_arguments['related_module']];
782
                if ( !empty($class) ) {
783
                    $rbean = new $class();
784
                    $rbean->id = $key;
785
                    $rbean->call_custom_logic('after_relationship_add', $custom_reverse_arguments);
786
                }
787
            }
788
		}
789
	}
790
791
	function _add_many_to_many($add_values) {
792
793
		//add date modified.
794
		$add_values['date_modified']=  $GLOBALS['timedate']->nowDb();
795
796
		//check whether duplicate exist or not.
797
		if ($this->relationship_exists($this->_relationship->join_table,$add_values)) {
798
799
/*			switch($this->when_dup_relationship_found) {
800
801
				case 1: //do nothing.
802
					$GLOBALS['log']->debug("Executing default option, no action.");
803
					break;
804
805
				case 3: //delete the record first, then create a new entry.
806
					$this->_delete_row($this->_relationship->join_table,$this->_duplicate_key);
807
					$this->_insert_row($add_values);
808
					break;
809
810
				default:
811
				case 2: //update the record.
812
*/					$this->_update_row($add_values,$this->_relationship->join_table,$this->_duplicate_where);
813
/*					break;
814
			}*/
815
816
		} else {
817
			$this->_insert_row($add_values);
818
		}
819
	}
820
821
	function _delete_row($table_name,$key) {
822
		$query="UPDATE $table_name SET deleted=1, date_modified='" .$GLOBALS['timedate']->nowDb()."' WHERE id='".$this->_db->quote($key)."'";
823
		$GLOBALS['log']->debug("Relationship Delete Statement :".$query);
824
825
		$result=$this->_db->query($query, true);
826
	}
827
828
	function _update_row(&$value_array,$table_name,$where) {
829
830
		$query='UPDATE '.$table_name.' SET ';
831
		$delimiter='';
832
		foreach ($value_array as $key=>$value) {
833
			$query.=$delimiter.$key."='".$this->_db->quote($value)."' ";
834
			$delimiter=",";
835
		}
836
		$query.=$where;
837
		$GLOBALS['log']->debug("Relationship Update Statement :".$query);
838
839
		$result=$this->_db->query($query, true);
840
	}
841
842
	function _insert_row(&$value_array) {
843
		//add key column
844
		$value_array['id']= create_guid();
845
846
		$columns_list='';
847
		$values_list='';
848
		$delimiter='';
849
		foreach ($value_array as $key=>$value) {
850
			$columns_list.=$delimiter.$key;
851
			$values_list .=$delimiter."'".$this->_db->quote($value)."'";
852
			$delimiter=",";
853
		}
854
		$insert_string='INSERT into '.$this->_relationship->join_table.' ('.$columns_list.') VALUES ('.$values_list.')';
855
		$GLOBALS['log']->debug("Relationship Insert String :".$insert_string);
856
857
		$result=$this->_db->query($insert_string, true);
858
	}
859
860
861
862
	/* This method operates on all related record, takes action based on cardinality of the relationship.
863
	 * one-to-one, one-to-many: update the rhs table's parent id with null
864
	 * many-to-one: update the lhs table's parent-id with null.
865
	 * many-to-many: delete rows from the link table. related table must have deleted and date_modified column.
866
	 * If related_id is null, the methods assumes that the parent bean (whose id is passed) is being deleted.
867
	 * If both id and related_id are passed, the method unlinks a single relationship.
868
	 * parameters: id of the bean being deleted.
869
	 *
870
	 */
871
	function delete($id,$related_id='') {
872
		$GLOBALS['log']->debug(sprintf("delete called with these parameter values. id=%s, related_id=%s",$id,$related_id));
873
874
		$_relationship=&$this->_relationship;
875
		$_bean=&$this->_bean;
876
877
		$bean_is_lhs=$this->_get_bean_position();
878
		if (!isset($bean_is_lhs)) {
879
			$GLOBALS['log']->debug("Invalid relationship parameters. Exiting..");
880
			return null;
881
		}
882
	    if ($_relationship->relationship_type=='one-to-many' or $_relationship->relationship_type=='one-to-one' ) {
883
    		if ($bean_is_lhs) {
884
    			//update rhs_table set rhs_key = null, relation_column_name = null where rhs_key= this_bean_id
885
    			$query='UPDATE '.$_relationship->rhs_table.' SET '.$_relationship->rhs_key."=NULL, date_modified='".$GLOBALS['timedate']->nowDb()."'";
886
887
    			if (!empty($_relationship->relationship_role_column) && !empty($_relationship->relationship_role_column_value)) {
888
    				$query.=','.$_relationship->relationship_role_column."= NULL ";
889
    				$query.=' WHERE '.$_relationship->relationship_role_column."= '".$_relationship->relationship_role_column_value."' AND ";
890
    			} else {
891
    				$query.=' WHERE ';
892
    			}
893
    			$query.=$_relationship->rhs_key."= '".$id."' ";
894
895
    			//restrict to one row if related_id is passed.
896
    			if (!empty($related_id)) {
897
    				$query.=" AND ".$_relationship->rhs_table.".id='".$related_id."'";
898
    			}
899
900
    		}
901
    		else {
0 ignored issues
show
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
902
    			//do nothing because the row that stores the relationship keys is being deleted.
903
    			//todo log an error message here.
904
    			//if this is the case and related_id is passed then log a message asking the user
905
    			//to clear the relationship using the bean.
906
    		}
907
	    }
908
909
		if ($_relationship->relationship_type=='many-to-one') {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
910
    		//do nothing because the row that stores the relationship keys is being deleted.
911
			//todo log an error message here.
912
   			//if this is the case and related_id is passed then log a message asking the user
913
   			//to clear the relationship using the bean.
914
		}
915
916
		if ($_relationship->relationship_type=='many-to-many' ) {
917
			$use_bean_is_lhs = isset($_REQUEST['ajaxSubpanel']) || $this->_swap_sides !== true;
918
    		$query='UPDATE '.$_relationship->join_table." SET deleted=1, date_modified='".$GLOBALS['timedate']->nowDb()."'";
919
    		if ($bean_is_lhs && $use_bean_is_lhs) {
920
    			if (!empty($this->_relationship->reverse) && ($this->_relationship->reverse == true or $this->_relationship->reverse == 1)){
921
    				if (empty($related_id)) {
922
    					$query.=" WHERE (".$_relationship->join_key_lhs."= '". $id ."' or ".$_relationship->join_key_rhs."='". $id ."')" ;
923
    				} else {
924
    					$query.=" WHERE (".$_relationship->join_key_lhs."= '". $id ."' AND ".$_relationship->join_key_rhs."='".$related_id."') OR (".$_relationship->join_key_rhs."='". $id ."' AND ".$_relationship->join_key_lhs."='".$related_id."')";
925
    				}
926
    			} else {
927
    				if (empty($related_id)) {
928
    					$query.=" WHERE ".$_relationship->join_key_lhs."= '". $id ."'";
929
    				} else {
930
    					$query.=" WHERE ".$_relationship->join_key_lhs."= '". $id ."' AND ".$_relationship->join_key_rhs."= '". $related_id."'";
931
    				}
932
    			}
933
    		} else {
934
                if (!empty($this->_relationship->reverse) && ($this->_relationship->reverse == true or $this->_relationship->reverse == 1)) {
935
                    if (empty($related_id)) {
936
                        $query.=" WHERE (".$_relationship->join_key_rhs."= '". $id ."' or ".$_relationship->join_key_lhs."='". $id ."')" ;
937
                    } else {
938
                        $query.=" WHERE (".$_relationship->join_key_rhs."= '". $id ."' AND ".$_relationship->join_key_lhs."='".$related_id."') OR (".$_relationship->join_key_lhs."='". $id ."' AND ".$_relationship->join_key_rhs."='".$related_id."')";
939
                    }
940
                } else {
941
                     if (empty($related_id)) {
942
                        $query.=" WHERE ".$_relationship->join_key_rhs."= '". $id ."'" ;
943
                     } else {
944
                        $query.=" WHERE ".$_relationship->join_key_rhs."= '". $id ."' AND ".$_relationship->join_key_lhs."= '". $related_id."'" ;
945
                     }
946
                }
947
    			if (!empty($_relationship->relationship_role_column) && !empty($_relationship->relationship_role_column_value)) {
948
    				$query.=' AND '.$_relationship->relationship_role_column."= '".$_relationship->relationship_role_column_value."'";
949
    			}
950
    		}
951
		}
952
		//if query string is not empty execute it.
953
		if (isset($query)) {
954
            $GLOBALS['log']->fatal('Link.Delete:Delete Query: '.$query);
955
			$this->_db->query($query,true);
956
		}
957
		$custom_logic_arguments = array();
958
		$custom_logic_arguments['id'] = $id;
959
		$custom_logic_arguments['related_id'] = $related_id;
960
		$custom_reverse_arguments = array();
961
		$custom_reverse_arguments['related_id'] = $id;
962
		$custom_reverse_arguments['id'] = $related_id;
963
		if($bean_is_lhs) {
964
			$custom_logic_arguments['module'] = $this->_relationship->lhs_module;
965
			$custom_logic_arguments['related_module'] = $this->_relationship->rhs_module;
966
			$custom_reverse_arguments['module'] = $this->_relationship->lhs_module;
967
			$custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module;
968
		} else {
969
			$custom_logic_arguments['module'] = $this->_relationship->rhs_module;
970
			$custom_logic_arguments['related_module'] = $this->_relationship->lhs_module;
971
			$custom_reverse_arguments['module'] = $this->_relationship->lhs_module;
972
			$custom_reverse_arguments['related_module'] = $this->_relationship->rhs_module;
973
		}
974
975
        if (empty($this->_bean->id)) {
976
            $this->_bean->retrieve($id);//!$bean_is_lhs || empty($related_id) ? $id : $related_id);
977
        }
978
        $this->_bean->call_custom_logic('after_relationship_delete', $custom_logic_arguments);
979
		//NOW THE REVERSE WAY SINCE A RELATIONSHIP TAKES TWO
980
		global $beanList;
981
		if ( isset($beanList[$custom_logic_arguments['related_module']]) ) {
982
            $class = $beanList[$custom_logic_arguments['related_module']];
983
            if ( !empty($class) ) {
984
                $rbean = new $class();
985
                $rbean->retrieve(empty($related_id) ? $id : $related_id);
986
                $rbean->call_custom_logic('after_relationship_delete', $custom_reverse_arguments);
987
            }
988
        }
989
	}
990
991
	function relationship_exists($table_name, $join_key_values) {
992
993
		//find the key values for the table.
994
		$dup_keys=$this->_get_alternate_key_fields($table_name);
995
		if (empty($dup_keys)) {
996
			$GLOBALS['log']->debug("No alternate key define, skipping duplicate check..");
997
			return false;
998
		}
999
1000
		$delimiter='';
1001
		$this->_duplicate_where=' WHERE ';
1002
		foreach ($dup_keys as $field) {
1003
			//look for key in  $join_key_values, if found add to filter criteria else abort duplicate checking.
1004
			if (isset($join_key_values[$field])) {
1005
1006
				$this->_duplicate_where .= $delimiter.' '.$field."='".$join_key_values[$field]."'";
1007
				$delimiter='AND';
1008
			} else {
1009
				$GLOBALS['log']->error('Duplicate checking aborted, Please supply a value for this column '.$field);
1010
				return false;
1011
			}
1012
		}
1013
		//add deleted check.
1014
		$this->_duplicate_where .= $delimiter.' deleted=0';
1015
1016
		$query='SELECT id FROM '.$table_name.$this->_duplicate_where;
1017
1018
		$GLOBALS['log']->debug("relationship_exists query(".$query.')');
1019
1020
		$result=$this->_db->query($query, true);
1021
		$row = $this->_db->fetchByAssoc($result);
1022
1023
		if ($row == null) {
1024
			return false;
1025
		}
1026
		else {
1027
			$this->_duplicate_key=$row['id'];
1028
			return true;
1029
		}
1030
	}
1031
1032
	/* returns array of keys for duplicate checking, first check for an index of type alternate_key, if not found searches for
1033
	 * primary key.
1034
	 *
1035
	 */
1036
	function _get_alternate_key_fields($table_name) {
1037
		$alternateKey=null;
1038
		$indices=Link::_get_link_table_definition($table_name,'indices');
1039
		if (!empty($indices)) {
1040
			foreach ($indices as $index) {
1041
                if ( isset($index['type']) && $index['type'] == 'alternate_key' ) {
1042
                    return $index['fields'];
1043
                }
1044
			}
1045
		}
1046
		$relationships=Link::_get_link_table_definition($table_name,'relationships');
1047
		if (!empty($relationships)) {//bug 32623, when the relationship is built in old version, there is no alternate_key. we have to use join_key_lhs and join_key_lhs.
1048
			if(!empty($relationships[$this->_relationship_name]) && !empty($relationships[$this->_relationship_name]['join_key_lhs']) && !empty($relationships[$this->_relationship_name]['join_key_rhs'])) {
1049
				return array($relationships[$this->_relationship_name]['join_key_lhs'], $relationships[$this->_relationship_name]['join_key_rhs']);
1050
			}
1051
		}
1052
	}
1053
1054
1055 1
	function _get_link_table_definition($table_name,$def_name) {
1056 1
	    global $dictionary;
1057
1058
        /*
1059
         * If this method is called statically will throw FATAL error on php7 because of the $this usage
1060
         */
1061 1
        $staticContext = !isset($this);
1062 1
        if($staticContext) {
1063 1
            return null;
1064
        }
1065
1066
		include_once('modules/TableDictionary.php');
1067
	    // first check to see if already loaded - assumes hasn't changed in the meantime
1068
        if (isset($dictionary[$table_name][$def_name]))
1069
        {
1070
            return $dictionary[$table_name][$def_name];
1071
        }
1072
        else {
1073
 			if (isset($dictionary[$this->_relationship_name][$def_name])) {
1074
 				return ($dictionary[$this->_relationship_name][$def_name]);
1075
 			}
1076
            // custom metadata is found in custom/metadata (naturally) and the naming follows the convention $relationship_name_c, and $relationship_name = $table_name$locations = array( 'metadata/' , 'custom/metadata/' ) ;
1077
            $relationshipName = preg_replace( '/_c$/' , '' , $table_name ) ;
1078
1079
            $locations = array ( 'metadata/' , 'custom/metadata/' ) ;
1080
1081
            foreach ( $locations as $basepath )
1082
            {
1083
                $path = $basepath . $relationshipName . 'MetaData.php' ;
1084
1085
                if (file_exists($path))
1086
                {
1087
                    include($path);
1088
                    if (isset($dictionary[$relationshipName][$def_name])) {
1089
                        return $dictionary[$relationshipName][$def_name];
1090
                    }
1091
                }
1092
            }
1093
            // couldn't find the metadata for the table in either the standard or custom locations
1094
            $GLOBALS['log']->debug('Error fetching field defs for join table '.$table_name);
1095
1096
            return null;
1097
        }
1098
1099
1100
1101
	}
1102
    /*
1103
     * Return the name of the role field for the passed many to many table.
1104
     * if there is no role filed : return false
1105
     */
1106
    function _get_link_table_role_field($table_name) {
1107
        $varDefs = $this->_get_link_table_definition($table_name, 'fields');
1108
        $role_field = false;
1109
        if(!empty($varDefs)){
1110
            $role_field = '';
1111
            foreach($varDefs as $v){
1112
                if(strpos($v['name'], '_role') !== false){
1113
                    $role_field = $v['name'];
1114
                }
1115
            }
1116
        }
1117
        return $role_field;
1118
    }
1119
1120
1121
}
1122
?>
1123