SugarFolder   D
last analyzed

Complexity

Total Complexity 151

Size/Duplication

Total Lines 978
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 4.9%

Importance

Changes 3
Bugs 3 Features 1
Metric Value
c 3
b 3
f 1
dl 0
loc 978
ccs 25
cts 510
cp 0.049
rs 4.4444
wmc 151
lcom 1
cbo 2

36 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A SugarFolder() 0 10 2
A deleteEmailFromAllFolder() 0 4 1
A deleteEmailFromFolder() 0 4 1
A checkEmailExistForFolder() 0 10 2
A move() 0 4 1
A copyBean() 0 5 1
A setFolder() 0 15 2
A getSubscriptions() 0 14 3
B setSubscriptions() 0 31 6
A insertFolderSubscription() 0 7 1
A getParentIDRecursive() 0 21 4
A clearSubscriptions() 0 8 2
A clearSubscriptionsForFolder() 0 5 1
A generateArchiveFolderQuery() 0 14 1
A generateSugarsDynamicFolderQuery() 0 21 4
F getListItemsForEmailXML() 0 68 13
B getCountItems() 0 25 3
B getCountUnread() 0 25 3
B addBean() 0 21 5
D retrieveFoldersForProcessing() 0 44 9
B getGroupFoldersForSettings() 0 19 5
C getFoldersForSettings() 0 44 8
B getFoldersChildForSettings() 0 27 6
A getCountNewItems() 0 6 1
D getUserFolders() 0 69 18
B buildTreeNodeRefresh() 0 24 5
D buildTreeNodeFolders() 0 42 10
A delete() 0 15 4
C deleteChildrenCascade() 0 50 7
C save() 0 40 7
A addSubscriptionsToGroupFolder() 0 7 1
A createSubscriptionForUser() 0 6 1
B updateFolder() 0 38 5
A findAllChildren() 0 16 3
A retrieve() 0 17 4

How to fix   Complexity   

Complex Class

Complex classes like SugarFolder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SugarFolder, and based on these observations, apply Extract Interface, too.

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:
44
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights
45
 * Reserved. Contributor(s): ______________________________________..
46
 *********************************************************************************/
47
48 1
require_once("include/ytree/Tree.php");
49 1
require_once("include/ytree/ExtNode.php");
50
51
/**
52
 * Polymorphic buckets - place any item in a folder
53
 */
54
class SugarFolder {
55
56
	// public attributes
57
	var $id;
58
	var $name;
59
	var $parent_folder;
60
	var $has_child = 0; // flag node has child
61
	var $is_group = 0;
62
	var $is_dynamic = 0;
63
	var $dynamic_query = '';
64
	var $assign_to_id;
65
	var $created_by;
66
	var $modified_by;
67
	var $date_created;
68
	var $date_modified;
69
	var $deleted;
70
	var $folder_type;
71
72
	var $db;
73
	var $new_with_id = false;
74
75
	// core queries
76
	var $core = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f left join inbound_email i on f.id = i.groupfolder_id ";
77
	var $coreSubscribed = "SELECT f.id, f.name, f.has_child, f.is_group, f.is_dynamic, f.dynamic_query, f.folder_type, f.created_by, i.deleted FROM folders f LEFT JOIN folders_subscriptions fs ON f.id = fs.folder_id LEFT JOIN inbound_email i on  i.groupfolder_id = f.id ";
78
	var $coreWhere = "WHERE f.deleted = 0 ";
79
	var $coreWhereSubscribed = "WHERE f.deleted = 0 AND fs.assigned_user_id = ";
80
	var $coreOrderBy = " ORDER BY f.is_dynamic, f.is_group, f.name ASC ";
81
82
	var $hrSortLocal = array(
83
            'flagged' => 'type',
84
            'status'  => 'reply_to_status',
85
            'from'    => 'emails_text.from_addr',
86
            'subject' => 'name',
87
            'date'    => 'date_sent',
88
            'AssignedTo' => 'assigned_user_id',
89
            'flagged' => 'flagged'
90
        );
91
    var $defaultSort = 'date';
92
    var $defaultDirection = "DESC";
93
94
	// private attributes
95
	var $_depth;
96
97
	/**
98
	 * Sole constructor
99
	 */
100 17
	function __construct() {
101 17
		$this->db = DBManagerFactory::getInstance();
102 17
	}
103
104
    /**
105
     * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
106
     */
107
    function SugarFolder(){
108
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
109
        if(isset($GLOBALS['log'])) {
110
            $GLOBALS['log']->deprecated($deprecatedMessage);
111
        }
112
        else {
113
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
114
        }
115
        self::__construct();
116
    }
117
118
119
	function deleteEmailFromAllFolder($id) {
120
		$q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' ";
121
		$r = $this->db->query($q);
122
	}
123
124
	function deleteEmailFromFolder($id) {
125
		$q = "delete from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
126
		$r = $this->db->query($q);
127
	}
128
129
	function checkEmailExistForFolder($id) {
130
		$q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
131
		$r = $this->db->query($q);
132
		$a = $this->db->fetchByAssoc($r);
133
		if ($a['c'] > 0) {
134
			return true;
135
		} else {
136
			return false;
137
		} // else
138
	}
139
	/**
140
	 * Moves beans from one folder to another folder
141
	 * @param string fromFolder GUID of source folder
142
	 * @param string toFolder GUID of destination folder
143
	 * @param string beanId GUID of SugarBean being moved
144
	 */
145
	function move($fromFolder, $toFolder, $beanId) {
146
		$q = "UPDATE folders_rel SET folder_id = '{$toFolder}' WHERE folder_id = '{$fromFolder}' AND polymorphic_id = '{$beanId}' AND deleted = 0";
147
		$r = $this->db->query($q);
148
	}
149
150
	/**
151
	 * Copies one bean from one folder to another
152
	 */
153
	function copyBean($fromFolder, $toFolder, $beanId, $module) {
154
		$q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
155
				VALUES('{$guid}', '{$toFolder}', '{$module}', '{$beanId}', 0)";
156
		$r = $this->db->query($q);
157
	}
158
159
	/**
160
	 * Creates a new group Folder from the passed fields
161
	 * @param array fields
162
	 */
163
	function setFolder($fields) {
164
165
		global $current_user;
166
		if(empty($fields['groupFoldersUser'])) {
167
			$fields['groupFoldersUser'] = $current_user->id;
168
		}
169
170
		$this->name = $fields['name'];
171
		$this->parent_folder = $fields['parent_folder'];
172
		$this->has_child = 0;
173
		$this->is_group = 1;
174
		$this->assign_to_id = $fields['groupFoldersUser'];
175
176
		$this->save();
177
	}
178
179
	/**
180
	 * Returns GUIDs of folders that the user in focus is subscribed to
181
	 * @param object user User object in focus
182
	 * @return array
183
	 */
184
	function getSubscriptions($user) {
185
		if(empty($user)) {
186
			global $current_user;
187
			$user = $current_user;
188
		}
189
190
		$q = "SELECT folder_id FROM folders_subscriptions WHERE assigned_user_id = '{$user->id}'";
191
		$r = $this->db->query($q);
192
		$ret = array();
193
		while($a = $this->db->fetchByAssoc($r)) {
194
			$ret[] = $a['folder_id'];
195
		}
196
		return $ret;
197
	}
198
199
	/**
200
	 * Sets a user's preferences for subscribe folders (Sugar only)
201
	 * @param array subs Array of IDs for subscribed folders
202
	 */
203
	function setSubscriptions($subs) {
204
		global $current_user;
205
206
		if(empty($current_user->id)) {
207
			$GLOBALS['log']->fatal("*** FOLDERS: tried to update folder subscriptions for a user with no ID");
208
			return false;
209
		}
210
211
		$cleanSubscriptions = array();
212
213
		// ensure parent folders are selected, regardless.
214
		foreach($subs as $id) {
215
			$id = trim($id);
216
			if(!empty($id)) {
217
				$cleanSubscriptions[] = $id;
218
				$qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
219
				$rChk = $this->db->query($qChk);
220
				$aChk = $this->db->fetchByAssoc($rChk);
221
222
				if(!empty($aChk['parent_folder'])) {
223
					$cleanSubscriptions = $this->getParentIDRecursive($aChk['parent_folder'], $cleanSubscriptions);
224
				}
225
			}
226
		}
227
228
		$this->clearSubscriptions();
229
230
		foreach($cleanSubscriptions as $id) {
231
		    $this->insertFolderSubscription($id, $current_user->id);
232
		}
233
	}
234
235
	/**
236
	 * Given a folder id and user id, create a folder subscription entry.
237
	 *
238
	 * @param String $folderId
239
	 * @param String $userID
240
	 * @return String The id of the newly created folder subscription.
241
	 */
242
	function insertFolderSubscription($folderId, $userID)
243
	{
244
	    $guid = create_guid();
245
		$query = "INSERT INTO folders_subscriptions (id, folder_id, assigned_user_id) VALUES ('{$guid}', '{$folderId}', '{$userID}')";
246
		$r = $this->db->query($query);
247
		return $guid;
248
	}
249
	/**
250
	 * Recursively finds parent node until it hits root
251
	 * @param string id Starting id to follow up
252
	 * @param array ret collected ids
253
	 * @return array of IDs
254
	 */
255
	function getParentIDRecursive($id, $ret=array()) {
256
		$q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
257
		$r = $this->db->query($q);
258
		$a = $this->db->fetchByAssoc($r);
259
260
		if(!in_array($id, $ret)) {
261
			$ret[] = $id;
262
		}
263
264
		if($a['parent_folder'] != '') {
265
			$qChk = "SELECT parent_folder FROM folders WHERE id = '{$id}'";
266
			$rChk = $this->db->query($qChk);
267
			$aChk = $this->db->fetchByAssoc($rChk);
268
269
			if(!empty($aChk['parent_folder'])) {
270
				$ret = $this->getParentIDRecursive($aChk['parent_folder'], $ret);
271
			}
272
		}
273
274
		return $ret;
275
	}
276
277
	/**
278
	 * Deletes subscriptions to folders in preparation for reset
279
	 */
280
	function clearSubscriptions() {
281
		global $current_user;
282
283
		if(!empty($current_user->id)) {
284
			$q = "DELETE FROM folders_subscriptions WHERE assigned_user_id = '{$current_user->id}'";
285
			$r = $this->db->query($q);
286
		}
287
	}
288
289
290
	/**
291
	 * Deletes all subscriptions for a particular folder id
292
	 *
293
	 * @return unknown
294
	 */
295
	function clearSubscriptionsForFolder($folderID)
296
	{
297
	    $query = "DELETE FROM folders_subscriptions WHERE folder_id = '$folderID'";
298
	    $r = $this->db->query($query);
299
	}
300
301
	protected function generateArchiveFolderQuery()
302
	{
303
		global $current_user;
304
	    $q = <<<ENDQ
305
SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails
306
JOIN emails_text on emails.id = emails_text.email_id
307
WHERE emails.deleted=0 AND emails.type NOT IN ('out', 'draft') AND emails.status NOT IN ('sent', 'draft') AND emails.id IN (
308
SELECT eear.email_id FROM emails_email_addr_rel eear
309
JOIN email_addr_bean_rel eabr ON eabr.email_address_id=eear.email_address_id AND eabr.bean_id = '{$current_user->id}' AND eabr.bean_module = 'Users'
310
WHERE eear.deleted=0
311
)
312
ENDQ;
313
        return $q;
314
	}
315
316
	function generateSugarsDynamicFolderQuery()
317
	{
318
		global $current_user;
319
		$type = $this->folder_type;
320
		if($type == 'archived') {
321
		    return $this->generateArchiveFolderQuery();
322
		}
323
		$status = $type;
324
		if($type == "sent") {
325
			$type = "out";
326
		}
327
		if($type == 'inbound') {
328
			$ret = " AND emails.status NOT IN ('sent', 'archived', 'draft') AND emails.type NOT IN ('out', 'archived', 'draft')";
329
		} else {
330
			$ret = " AND emails.status NOT IN ('archived') AND emails.type NOT IN ('archived')";
331
		}
332
		$q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails" .
333
								   " JOIN emails_text on emails.id = emails_text.email_id
334
                                   WHERE (type = '{$type}' OR status = '{$status}') AND assigned_user_id = '{$current_user->id}' AND emails.deleted=0";
335
		return $q . $ret;
336
	} // fn
337
338
339
	/**
340
	 * returns array of items for listView display in yui-ext Grid
341
	 */
342
	function getListItemsForEmailXML($folderId, $page = 1, $pageSize = 10, $sort = '', $direction='') {
343
		require_once('include/TimeDate.php');
344
		global $timedate;
345
		global $current_user;
346
		global $beanList;
347
		global $sugar_config;
348
		global $app_strings;
349
350
		$this->retrieve($folderId);
351
		$start = ($page - 1) * $pageSize;
352
353
		$sort = (empty($sort)) ? $this->defaultSort : $sort;
354
        if (!in_array(strtolower($direction), array('asc', 'desc'))) {
355
            $direction = $this->defaultDirection;
356
        }
357
358
        if (!empty($this->hrSortLocal[$sort])) {
359
            $order = " ORDER BY {$this->hrSortLocal[$sort]} {$direction}";
360
        } else {
361
            $order = "";
362
        }
363
364
		if($this->is_dynamic) {
365
			$r = $this->db->limitQuery(from_html($this->generateSugarsDynamicFolderQuery() . $order), $start, $pageSize);
366
		} else {
367
			// get items and iterate through them
368
			$q = "SELECT emails.id , emails.name, emails.date_sent, emails.status, emails.type, emails.flagged, emails.reply_to_status, emails_text.from_addr, emails_text.to_addrs, 'Emails' polymorphic_module FROM emails JOIN folders_rel ON emails.id = folders_rel.polymorphic_id" .
369
				  " JOIN emails_text on emails.id = emails_text.email_id
370
                  WHERE folders_rel.folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0";
371
			if ($this->is_group) {
372
				$q = $q . " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
373
			}
374
			$r = $this->db->limitQuery($q . $order, $start, $pageSize);
375
		}
376
377
		$return = array();
378
379
		$email = new Email(); //Needed for email specific functions.
380
381
		while($a = $this->db->fetchByAssoc($r)) {
382
383
			$temp = array();
384
			$temp['flagged'] = (is_null($a['flagged']) || $a['flagged'] == '0') ? '' : 1;
385
			$temp['status'] = (is_null($a['reply_to_status']) || $a['reply_to_status'] == '0') ? '' : 1;
386
			$temp['from']	= preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['from_addr']);
387
			$temp['subject'] = $a['name'];
388
			$temp['date']	= $timedate->to_display_date_time($this->db->fromConvert($a['date_sent'], 'datetime'));
389
			$temp['uid'] = $a['id'];
390
			$temp['mbox'] = 'sugar::'.$a['polymorphic_module'];
391
			$temp['ieId'] = $folderId;
392
			$temp['site_url'] = $sugar_config['site_url'];
393
			$temp['seen'] = ($a['status'] == 'unread') ? 0 : 1;
394
			$temp['type'] = $a['type'];
395
			$temp['hasAttach'] = $email->doesImportedEmailHaveAttachment($a['id']);
396
			$temp['to_addrs'] = preg_replace('/[\x00-\x08\x0B-\x1F]/', '', $a['to_addrs']);
397
			$return[] = $temp;
398
		}
399
400
401
		$metadata = array();
402
		$metadata['mbox'] = $app_strings['LBL_EMAIL_SUGAR_FOLDER'].': '.$this->name;
403
		$metadata['ieId'] = $folderId;
404
		$metadata['name'] = $this->name;
405
		$metadata['unreadChecked'] = ($current_user->getPreference('showUnreadOnly', 'Emails') == 1) ? 'CHECKED' : '';
406
		$metadata['out'] = $return;
407
408
		return $metadata;
409
	}
410
411
	function getCountItems ( $folderId ) {
412
		global $current_user ;
413
		global $beanList ;
414
		global $sugar_config ;
415
		global $app_strings ;
416
417
		$this->retrieve ( $folderId ) ;
418
		if ($this->is_dynamic) {
419
	    	$pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
420
	    	$replacement = 'SELECT count(*) c FROM ';
421
	    	$modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
422
	    	$r = $this->db->query ( from_html ( $modified_select_query )) ;
423
		} else {
424
			// get items and iterate through them
425
			$q = "SELECT count(*) c FROM folders_rel JOIN emails ON emails.id = folders_rel.polymorphic_id" .
426
			" WHERE folder_id = '{$folderId}' AND folders_rel.deleted = 0 AND emails.deleted = 0" ;
427
			if ($this->is_group) {
428
				$q .= " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
429
			}
430
			$r = $this->db->query ( $q ) ;
431
		}
432
433
		$a = $this->db->fetchByAssoc($r);
434
		return $a['c'];
435
	}
436
437
    function getCountUnread ( $folderId ) {
438
        global $current_user ;
439
        global $beanList ;
440
        global $sugar_config ;
441
        global $app_strings ;
442
443
        $this->retrieve ( $folderId ) ;
444
        if ($this->is_dynamic) {
445
	    	$pattern = '/SELECT(.*?)(\s){1}FROM(\s){1}/is';  // ignores the case
446
	    	$replacement = 'SELECT count(*) c FROM ';
447
	    	$modified_select_query = preg_replace($pattern, $replacement, $this->generateSugarsDynamicFolderQuery(), 1);
448
	    	$r = $this->db->query (from_html($modified_select_query) . " AND emails.status = 'unread'") ;
449
        } else {
450
            // get items and iterate through them
451
            $q = "SELECT count(*) c FROM folders_rel fr JOIN emails on fr.folder_id = '{$folderId}' AND fr.deleted = 0 " .
452
               "AND fr.polymorphic_id = emails.id AND emails.status = 'unread' AND emails.deleted = 0" ;
453
            if ($this->is_group) {
454
                $q .= " AND (emails.assigned_user_id is null or emails.assigned_user_id = '')";
455
            }
456
            $r = $this->db->query ( $q ) ;
457
        }
458
459
		$a = $this->db->fetchByAssoc($r);
460
        return $a['c'];
461
    }
462
463
464
	/**
465
	 * Convenience method, pass a SugarBean and User to this to add anything to a given folder
466
	 */
467
	function addBean($bean, $user=null) {
468
		if(empty($bean->id) || empty($bean->module_dir)) {
469
			$GLOBALS['log']->fatal("*** FOLDERS: addBean() got empty bean - not saving");
470
			return false;
471
		} elseif(empty($this->id)) {
472
			$GLOBALS['log']->fatal("*** FOLDERS: addBean() is trying to save to a non-saved or non-existent folder");
473
			return false;
474
		}
475
476
		global $current_user;
477
		if($user == null) {
478
			$user = $current_user;
479
		}
480
481
		$guid = create_guid();
482
483
		$q = "INSERT INTO folders_rel (id, folder_id, polymorphic_module, polymorphic_id, deleted)
484
				VALUES('{$guid}', '{$this->id}', '{$bean->module_dir}', '{$bean->id}', 0)";
485
		$r = $this->db->query($q);
486
		return true;
487
	}
488
489
	/**
490
	 * Builds up a metacollection of user/group folders to be passed to processor methods
491
	 * @param object User object, defaults to $current_user
492
	 * @return array Array of abstract folder objects
493
	 */
494
	function retrieveFoldersForProcessing($user, $subscribed=true) {
495
		global $sugar_config;
496
		global $current_language, $current_user;
497
498
		$emails_mod_strings = return_module_language($current_language, "Emails");
499
		$myEmailTypeString = 'inbound';
500
		$myDraftsTypeString = 'draft';
501
		$mySentEmailTypeString = 'sent';
502
503
		if(empty($user)) {
504
			global $current_user;
505
			$user = $current_user;
506
		}
507
		$rootWhere = '';
508
        $teamSecurityClause = '';
509
510
511
512
    	$rootWhere .= "AND (f.parent_folder IS NULL OR f.parent_folder = '')";
513
514
		if($subscribed) {
515
			$q = $this->coreSubscribed.$teamSecurityClause.$this->coreWhereSubscribed."'{$user->id}' ".$rootWhere.$this->coreOrderBy;
516
		} else {
517
			$q = $this->core.$teamSecurityClause.$this->coreWhere.$rootWhere.$this->coreOrderBy;
518
		}
519
		$r = $this->db->query($q);
520
		$return = array();
521
522
		$found = array();
523
		while($a = $this->db->fetchByAssoc($r)) {
524
			if ((($a['folder_type'] == $myEmailTypeString) ||
525
				($a['folder_type'] == $myDraftsTypeString) ||
526
				($a['folder_type'] == $mySentEmailTypeString)) &&
527
				($a['created_by'] != $current_user->id)) {
528
529
				continue;
530
			} // if
531
			if (!isset($found[$a['id']])) {
532
                $found[$a['id']] = true;
533
			    $return[] = $a;
534
			}
535
		}
536
		return $return;
537
	}
538
    /**
539
	 * Preps object array for async call from user's Settings->Folders
540
	 */
541
	function getGroupFoldersForSettings($focusUser=null) {
542
		global $app_strings;
543
544
		$grp = array();
545
546
		$folders = $this->retrieveFoldersForProcessing($focusUser, false);
547
		$subscriptions = $this->getSubscriptions($focusUser);
548
549
		foreach($folders as $a) {
550
			$a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
551
            $a['origName'] = $a['name'];
552
553
			if($a['is_group'] == 1)
554
				if ($a['deleted'] != 1)
555
					$grp[] = $a;
556
		}
557
558
		return $grp;
559
	}
560
	/**
561
	 * Preps object array for async call from user's Settings->Folders
562
	 */
563
	function getFoldersForSettings($focusUser=null) {
564
		global $app_strings;
565
566
		$user = array();
567
		$grp = array();
568
		$user[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 0, 'selected' => false);
569
		$grp[] = array('id' => '', 'name' => $app_strings['LBL_NONE'], 'has_child' => 0, 'is_group' => 1, 'selected' => false, 'origName' => "");
570
571
		$folders = $this->retrieveFoldersForProcessing($focusUser, false);
572
		$subscriptions = $this->getSubscriptions($focusUser);
573
574
		foreach($folders as $a) {
575
			$a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
576
            $a['origName'] = $a['name'];
577
            if( isset($a['dynamic_query']) )
578
                unset($a['dynamic_query']);
579
			if($a['is_group'] == 1) {
580
				$grp[] = $a;
581
			} else {
582
				$user[] = $a;
583
			}
584
585
			if($a['has_child'] == 1) {
586
				$qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
587
				$rGetChildren = $this->db->query($qGetChildren);
588
589
				while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
590
					if($a['is_group']) {
591
						$this->_depth = 1;
592
						$grp = $this->getFoldersChildForSettings($aGetChildren, $grp, $subscriptions);
593
					} else {
594
						$this->_depth = 1;
595
						$user = $this->getFoldersChildForSettings($aGetChildren, $user, $subscriptions);
596
					}
597
				}
598
			}
599
		}
600
601
		$ret = array(
602
			'userFolders'	=> $user,
603
			'groupFolders'	=> $grp,
604
		);
605
		return $ret;
606
	}
607
608
	function getFoldersChildForSettings($a, $collection, $subscriptions) {
609
		$a['selected'] = (in_array($a['id'], $subscriptions)) ? true : false;
610
		$a['origName'] = $a['name'];
611
612
		if(isset($a['dynamic_query']))
613
		{
614
		   unset($a['dynamic_query']);
615
		}
616
617
		for($i=0; $i<$this->_depth; $i++)
618
		{
619
			$a['name'] = ".".$a['name'];
620
		}
621
622
		$collection[] = $a;
623
624
		if($a['has_child'] == 1) {
625
			$this->_depth++;
626
			$qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
627
			$rGetChildren = $this->db->query($qGetChildren);
628
			while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
629
				$collection = $this->getFoldersChildForSettings($aGetChildren, $collection, $subscriptions);
630
			}
631
		}
632
633
		return $collection;
634
	}
635
636
	/**
637
	 * Returns the number of "new" items (based on passed criteria)
638
	 * @param string id ID of folder
639
	 * @param array criteria
640
	 * 		expected:
641
	 * 		array('field' => 'status',
642
	 * 				'value' => 'unread');
643
	 * @param array
644
	 * @return int
645
	 */
646
	function getCountNewItems($id, $criteria, $folder) {
647
		global $current_user;
648
649
		$sugarFolder = new SugarFolder();
650
		return $sugarFolder->getCountUnread($id);
651
	}
652
653
	/**
654
	 * Collects, sorts, and builds tree of user's folders
655
	 * @param objec $rootNode Reference to tree root node
656
	 * @param array $folderStates User pref folder open/closed states
657
	 * @param object $user Optional User in focus, default current_user
658
	 * @return array
659
	 */
660
	function getUserFolders(&$rootNode, $folderStates, $user=null, $forRefresh=false) {
661
		if(empty($user)) {
662
			global $current_user;
663
			$user = $current_user;
664
		}
665
		global $mod_strings;
666
		$folders = $this->retrieveFoldersForProcessing($user, true);
667
		$subscriptions = $this->getSubscriptions($user);
668
669
		$refresh = ($forRefresh) ? array() : null;
670
671
		if(!is_array($folderStates)) {
672
			$folderStates = array();
673
		}
674
675
		foreach($folders as $a) {
676
			if ($a['deleted'] == 1)
677
				continue;
678
			$label = ($a['name'] == 'My Email' ? $mod_strings['LNK_MY_INBOX'] : $a['name']);
679
680
			$unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
681
682
			$folderNode = new ExtNode($a['id'], $label);
683
			$folderNode->dynamicloadfunction = '';
684
			$folderNode->expanded = false;
685
686
			if(array_key_exists('Home::'.$a['id'], $folderStates)) {
687
				if($folderStates['Home::'.$a['id']] == 'open') {
688
					$folderNode->expanded = true;
689
				}
690
			}
691
			$nodePath = "Home::".$folderNode->_properties['id'];
692
693
			$folderNode->dynamic_load = true;
694
	        //$folderNode->set_property('click', " SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
695
	        $folderNode->set_property('ieId', 'folder');
696
	        $folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
697
	        $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
698
	        $folderNode->set_property('mbox', $folderNode->_properties['id']);
699
	        $folderNode->set_property('unseen', $unseen);
700
	        $folderNode->set_property('id', $a['id']);
701
	        $folderNode->set_property('folder_type', $a['folder_type']);
702
	        $folderNode->set_property('children', array());
703
704
			if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
705
				$qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}'";
706
				$rGetChildren = $this->db->query($qGetChildren);
707
708
				while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
709
					if(in_array($aGetChildren['id'], $subscriptions)) {
710
						$folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
711
					}
712
				}
713
			}
714
			$rootNode->add_node($folderNode);
715
		}
716
717
		/* the code below is called only by Settings->Folders when selecting folders to subscribe to */
718
		if($forRefresh) {
719
			$metaNode = array();
720
721
			if(!empty($rootNode->nodes)) {
722
				foreach($rootNode->nodes as $node) {
723
					$metaNode[] = $this->buildTreeNodeRefresh($node, $subscriptions);
724
				}
725
			}
726
			return $metaNode;
727
		}
728
	}
729
730
	/**
731
	 * Builds up a metanode for folder refresh (Sugar folders only)
732
	 */
733
	function buildTreeNodeRefresh($folderNode, $subscriptions) {
734
		$metaNode = $folderNode->_properties;
735
		$metaNode['expanded'] = $folderNode->expanded;
736
		$metaNode['text'] = $folderNode->_label;
737
		if($metaNode['is_group'] == 'true') {
738
			$metaNode['cls'] = 'groupFolder';
739
		} else {
740
		    $metaNode['cls'] = 'sugarFolder';
741
		}
742
		$metaNode['id'] = $folderNode->_properties['id'];
743
		$metaNode['children'] = array();
744
		$metaNode['type'] = 1;
745
		$metaNode['leaf'] = false;
746
		$metaNode['isTarget'] = true;
747
		$metaNode['allowChildren'] = true;
748
749
		if(!empty($folderNode->nodes)) {
750
			foreach($folderNode->nodes as $node) {
751
				if(in_array($node->_properties['id'], $subscriptions))
752
					$metaNode['children'][] = $this->buildTreeNodeRefresh($node, $subscriptions);
753
			}
754
		}
755
		return $metaNode;
756
	}
757
758
	/**
759
	 * Builds children nodes for folders for TreeView
760
	 * @return $folderNode TreeView node
0 ignored issues
show
Documentation introduced by
The doc-type $folderNode could not be parsed: Unknown type name "$folderNode" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
761
	 */
762
	function buildTreeNodeFolders($a, $nodePath, $folderStates, $subscriptions) {
763
		$label = $a['name'];
764
		global $mod_strings;
765
		if($a['name'] == 'My Drafts') {
766
			$label = $mod_strings['LBL_LIST_TITLE_MY_DRAFTS'];
767
		}
768
		if($a['name'] == 'Sent Emails') {
769
			$label = $mod_strings['LBL_LIST_TITLE_MY_SENT'];
770
		}
771
		$unseen = $this->getCountNewItems($a['id'], array('field' => 'status', 'value' => 'unread'), $a);
772
773
		$folderNode = new ExtNode($a['id'], $label);
774
		$folderNode->dynamicloadfunction = '';
775
		$folderNode->expanded = false;
776
777
		$nodePath .= "::{$a['id']}";
778
779
		if(array_key_exists($nodePath, $folderStates)) {
780
			if($folderStates[$nodePath] == 'open') {
781
				$folderNode->expanded = true;
782
			}
783
		}
784
785
		$folderNode->dynamic_load = true;
786
        $folderNode->set_property('click', "SUGAR.email2.listView.populateListFrameSugarFolder(YAHOO.namespace('frameFolders').selectednode, '{$a['id']}', 'false');");
787
        $folderNode->set_property('ieId', 'folder');
788
        $folderNode->set_property('mbox', $a['id']);
789
		$folderNode->set_property('is_group', ($a['is_group'] == 1) ? 'true' : 'false');
790
        $folderNode->set_property('is_dynamic', ($a['is_dynamic'] == 1) ? 'true' : 'false');
791
        $folderNode->set_property('unseen', $unseen);
792
	    $folderNode->set_property('folder_type', $a['folder_type']);
793
794
		if(in_array($a['id'], $subscriptions) && $a['has_child'] == 1) {
795
			$qGetChildren = $this->core.$this->coreWhere."AND parent_folder = '{$a['id']}' ".$this->coreOrderBy;
796
			$rGetChildren = $this->db->query($qGetChildren);
797
798
			while($aGetChildren = $this->db->fetchByAssoc($rGetChildren)) {
799
				$folderNode->add_node($this->buildTreeNodeFolders($aGetChildren, $nodePath, $folderStates, $subscriptions));
800
			}
801
		}
802
		return $folderNode;
803
	}
804
805
	/**
806
	 * Flags a folder as deleted
807
	 * @return bool True on success
808
	 */
809
	function delete() {
810
		global $current_user;
811
812
		if(!empty($this->id)) {
813
			if($this->has_child) {
814
				$this->deleteChildrenCascade($this->id);
815
			}
816
817
			$ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
818
			$q = "UPDATE folders SET deleted = 1 WHERE id = '{$this->id}'{$ownerCheck}";
819
			$r = $this->db->query($q);
820
			return true;
821
		}
822
		return false;
823
	}
824
825
	/**
826
	 * Deletes all children in a cascade
827
	 * @param string $id ID of parent
828
	 * @return bool True on success
829
	 */
830
	function deleteChildrenCascade($id) {
831
		global $current_user;
832
833
		$canContinue = true;
834
		$checkInboundQuery = "SELECT count(*) c FROM inbound_email WHERE groupfolder_id = '{$id}' and deleted = 0";
835
		$resultSet = $this->db->query($checkInboundQuery);
836
		$a = $this->db->fetchByAssoc($resultSet);
837
		if ($a['c'] > 0) {
838
			return false;
839
		} // if
840
841
		$q = "SELECT COUNT(*) c from folders_rel where polymorphic_module = 'Emails' AND polymorphic_id = '{$id}' AND folder_id = '{$this->id}'";
842
843
		$checkEmailQuery = "SELECT count(*) c FROM folders_rel where polymorphic_module = 'Emails' and folder_id = '{$id}' and deleted = 0";
844
		$resultSet = $this->db->query($checkEmailQuery);
845
		$a = $this->db->fetchByAssoc($resultSet);
846
		if ($a['c'] > 0) {
847
			return false;
848
		} // if
849
850
		$q = "SELECT * FROM folders WHERE id = '{$id}'";
851
		$r = $this->db->query($q);
852
		$a = $this->db->fetchByAssoc($r);
853
854
		if($a['has_child'] == 1) {
855
			$q2 = "SELECT id FROM folders WHERE parent_folder = '{$id}'";
856
			$r2 = $this->db->query($q2);
857
858
			while($a2 = $this->db->fetchByAssoc($r2)) {
859
				$canContinue = $this->deleteChildrenCascade($a2['id']);
860
			}
861
		}
862
863
		if ($canContinue) {
864
			// flag deleted
865
			$ownerCheck = ($current_user->is_admin == 0) ? " AND created_by = '{$current_user->id}'" : "";
866
			$q3 = "UPDATE folders SET deleted = 1 WHERE id = '{$id}'{$ownerCheck}";
867
			$r3 = $this->db->query($q3);
868
869
			// flag rels
870
			$qRel = "UPDATE folders_rel SET deleted = 1 WHERE folder_id = '{$id}'";
871
			$rRel = $this->db->query($qRel);
872
873
			// delete subscriptions
874
			$qSub = "DELETE FROM folders_subscriptions WHERE folder_id = '{$id}'";
875
			$rSub = $this->db->query($qSub);
876
		}
877
		return $canContinue;
878
		//_pp($q3);_pp($qRel);_pp($qSub);
879
	}
880
881
882
	/**
883
	 * Saves folder
884
	 * @return bool
885
	 */
886 1
	function save($addSubscriptions = TRUE) {
887 1
		global $current_user;
888
889 1
		$this->dynamic_query = $this->db->quote($this->dynamic_query);
890
891 1
		if((empty($this->id) && $this->new_with_id == false) || (!empty($this->id) && $this->new_with_id == true))
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
892
		{
893
894 1
		    if( empty($this->id) )
895
		    {
896
			    $guid = create_guid();
897
			    $this->id = $guid;
898
		    }
899
900
			$q = "INSERT INTO folders(id, name, folder_type, parent_folder, has_child, is_group, is_dynamic, dynamic_query, assign_to_id, ".
901
				"created_by, modified_by, deleted)".
902
903 1
				" VALUES('{$this->id}', '{$this->name}', '{$this->folder_type}', '{$this->parent_folder}', {$this->has_child}, {$this->is_group}, {$this->is_dynamic}, '{$this->dynamic_query}', '{$this->assign_to_id}', " .
904 1
				"'{$current_user->id}', '{$current_user->id}', 0)";
905
906
907 1
			if($addSubscriptions)
908
			{
909
			    // create default subscription
910 1
			    $this->addSubscriptionsToGroupFolder();
911
			}
912
913
			// if parent_id is set, update parent's has_child flag
914 1
			$q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
915 1
			$r3 = $this->db->query($q3);
916
		}
917
		else {
918
			$q = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', dynamic_query = '{$this->dynamic_query}', assign_to_id = '{$this->assign_to_id}', " .
919
				"modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
920
		}
921
922 1
		$this->db->query($q, true);
923
924 1
		return true;
925
	}
926
927
	/**
928
	 * Add subscriptions to this group folder.
929
	 *
930
	 */
931 1
	function addSubscriptionsToGroupFolder()
932
	{
933 1
	    global $current_user;
934
935 1
	    $this->createSubscriptionForUser($current_user->id);
936
937 1
	}
938
939
940
941
    /**
942
	 * Add subscriptions to this group folder.
943
	 *
944
	 */
945 1
	function createSubscriptionForUser($user_id)
946
	{
947 1
	   $guid2 = create_guid();
948 1
	   $query = "INSERT INTO folders_subscriptions VALUES('{$guid2}', '{$this->id}', '{$user_id}')";
949 1
	   $this->db->query($query);
950 1
	}
951
952
953
	function updateFolder($fields) {
954
		global $current_user;
955
956
		$this->dynamic_query = $this->db->quote($this->dynamic_query);
957
		$id = $fields['record'];
958
		$name = $fields['name'];
959
		$parent_folder = $fields['parent_folder'];
960
		// first do the retrieve
961
		$this->retrieve($id);
962
		if ($this->has_child) {
963
			$childrenArray = array();
964
			$this->findAllChildren($id, $childrenArray);
965
			if (in_array($parent_folder, $childrenArray)) {
966
				return array('status' => "failed", 'message' => "Can not add this folder to its children");
967
			}
968
		}
969
		// update has_child to 0 for this parent folder if this is the only child it has
970
		$q1 = "select count(*) count from folders where deleted = 0 AND parent_folder = '{$this->parent_folder}'";
971
		$r1 = $this->db->query($q1);
972
		$a1 = $this->db->fetchByAssoc($r1);
973
		if ($a1['count'] == 1) {
974
			$q1 = "UPDATE folders SET has_child = 0 WHERE id = '{$this->parent_folder}'";
975
			$r1 = $this->db->query($q1);
976
		} // if
977
978
979
		$this->name = $name;
980
		$this->parent_folder = $parent_folder;
981
		$q2 = "UPDATE folders SET name = '{$this->name}', parent_folder = '{$this->parent_folder}', 			dynamic_query = '{$this->dynamic_query}', " .
982
			"modified_by = '{$current_user->id}' WHERE id = '{$this->id}'";
983
		$r2 = $this->db->query($q2);
984
		if (!empty($this->parent_folder)) {
985
			$q3 = "UPDATE folders SET has_child = 1 WHERE id = '{$this->parent_folder}'";
986
			$r3 = $this->db->query($q3);
987
		} // if
988
		return array('status' => "done");
989
990
	} // fn
991
992
	function findAllChildren($folderId, &$childrenArray) {
993
		$q = "SELECT * FROM folders WHERE id = '{$folderId}'";
994
		$r = $this->db->query($q);
995
		$a = $this->db->fetchByAssoc($r);
996
997
		if($a['has_child'] == 1) {
998
			$q2 = "SELECT id FROM folders WHERE deleted = 0 AND parent_folder = '{$folderId}'";
999
			$r2 = $this->db->query($q2);
1000
1001
			while($a2 = $this->db->fetchByAssoc($r2)) {
1002
				$childrenArray[] = $a2['id'];
1003
				$this->findAllChildren($a2['id'], $childrenArray);
1004
			} // while
1005
		} // if
1006
1007
	} // fn
1008
1009
	/**
1010
	 * Retrieves and populates object
1011
	 * @param string $id ID of folder
1012
	 * @return bool True on success
1013
	 */
1014
	function retrieve($id) {
1015
		$q = "SELECT * FROM folders WHERE id = '{$id}' AND deleted = 0";
1016
		$r = $this->db->query($q);
1017
		$a = $this->db->fetchByAssoc($r);
1018
1019
		if(!empty($a)) {
1020
			foreach($a as $k => $v) {
1021
				if($k == 'dynamic_query') {
1022
					$v = from_html($v);
1023
				}
1024
				$this->$k = $v;
1025
			}
1026
			return true;
1027
		}
1028
1029
		return false;
1030
	}
1031
} // end class def
1032