FolderChange::Handle()   F
last analyzed

Complexity

Conditions 40
Paths > 20000

Size

Total Lines 225
Code Lines 122

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 40
eloc 122
nc 336113
nop 1
dl 0
loc 225
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2024 grommunio GmbH
6
 *
7
 * Provides the FOLDERCREATE, FOLDERDELETE, FOLDERUPDATE command
8
 */
9
10
class FolderChange extends RequestProcessor {
11
	/**
12
	 * Handles creates, updates or deletes of a folder
13
	 * issued by the commands FolderCreate, FolderUpdate and FolderDelete.
14
	 *
15
	 * @param int $commandCode
16
	 *
17
	 * @return bool
18
	 */
19
	public function Handle($commandCode) {
20
		$el = self::$decoder->getElement();
21
22
		if ($el[EN_TYPE] != EN_TYPE_STARTTAG) {
23
			return false;
24
		}
25
26
		$create = $update = $delete = false;
27
		if ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERCREATE) {
28
			$create = true;
29
		}
30
		elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE) {
31
			$update = true;
32
		}
33
		elseif ($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE) {
34
			$delete = true;
35
		}
36
37
		if (!$create && !$update && !$delete) {
38
			return false;
39
		}
40
41
		// SyncKey
42
		if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) {
43
			return false;
44
		}
45
		$synckey = self::$decoder->getElementContent();
46
		if (!self::$decoder->getElementEndTag()) {
47
			return false;
48
		}
49
50
		// ServerID
51
		$serverid = false;
52
		$backendid = false;
53
		if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID)) {
54
			$serverid = self::$decoder->getElementContent();
55
			$backendid = self::$deviceManager->GetBackendIdForFolderId($serverid);
56
			if (!self::$decoder->getElementEndTag()) {
57
				return false;
58
			}
59
		}
60
61
		// Parent
62
		$parentid = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $parentid is dead and can be removed.
Loading history...
63
		$parentBackendId = false;
64
65
		// when creating or updating more information is necessary
66
		if (!$delete) {
67
			if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_PARENTID)) {
68
				$parentid = self::$decoder->getElementContent();
69
				$parentBackendId = self::$deviceManager->GetBackendIdForFolderId($parentid);
70
				if (!self::$decoder->getElementEndTag()) {
71
					return false;
72
				}
73
			}
74
75
			// Displayname
76
			if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_DISPLAYNAME)) {
77
				return false;
78
			}
79
			$displayname = self::$decoder->getElementContent();
80
			if (!self::$decoder->getElementEndTag()) {
81
				return false;
82
			}
83
84
			// Type
85
			$type = false;
86
			if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_TYPE)) {
87
				$type = self::$decoder->getElementContent();
88
				if (!self::$decoder->getElementEndTag()) {
89
					return false;
90
				}
91
			}
92
		}
93
94
		// endtag foldercreate, folderupdate, folderdelete
95
		if (!self::$decoder->getElementEndTag()) {
96
			return false;
97
		}
98
99
		$status = SYNC_FSSTATUS_SUCCESS;
100
		// Get state of hierarchy
101
		try {
102
			$syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey);
103
			$newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey);
104
105
			// there are no SyncParameters for the hierarchy, but we use it to save the latest synckeys
106
			$spa = self::$deviceManager->GetStateManager()->GetSynchedFolderState(false);
107
108
			// Over the ChangesWrapper the HierarchyCache is notified about all changes
109
			$changesMem = self::$deviceManager->GetHierarchyChangesWrapper();
110
111
			// the hierarchyCache should now fully be initialized - check for changes in the additional folders
112
			$changesMem->Config(GSync::GetAdditionalSyncFolders(false));
113
114
			// reset to default store in backend
115
			self::$backend->Setup(false);
116
117
			// there are unprocessed changes in the hierarchy, trigger resync
118
			if ($changesMem->GetChangeCount() > 0) {
119
				throw new StatusException("HandleFolderChange() can not proceed as there are unprocessed hierarchy changes", SYNC_FSSTATUS_SERVERERROR);
120
			}
121
122
			// any additional folders can not be modified - with exception if they are of type SYNC_FOLDER_TYPE_UNKNOWN
123
			if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && $serverid !== false && GSync::GetAdditionalSyncFolderStore($backendid)) {
124
				throw new StatusException("HandleFolderChange() can not change additional folders which are configured", SYNC_FSSTATUS_SYSTEMFOLDER);
125
			}
126
127
			// switch user store if this this happens inside an additional folder
128
			// if this is an additional folder the backend has to be setup correctly
129
			// backend should also not be switched when type is SYNC_FOLDER_TYPE_UNKNOWN
130
			if (self::$deviceManager->GetFolderTypeFromCacheById($serverid) != SYNC_FOLDER_TYPE_UNKNOWN && !self::$backend->Setup(GSync::GetAdditionalSyncFolderStore(($parentBackendId != false) ? $parentBackendId : $backendid))) {
131
				throw new StatusException(sprintf("HandleFolderChange() could not Setup() the backend for folder id '%s'", ($parentBackendId != false) ? $parentBackendId : $backendid), SYNC_FSSTATUS_SERVERERROR);
132
			}
133
		}
134
		catch (StateNotFoundException $snfex) {
135
			$status = SYNC_FSSTATUS_SYNCKEYERROR;
136
		}
137
		catch (StatusException $stex) {
138
			$status = $stex->getCode();
139
		}
140
141
		// set $newsynckey in case of an error
142
		if (!isset($newsynckey)) {
143
			$newsynckey = $synckey;
144
		}
145
146
		if ($status == SYNC_FSSTATUS_SUCCESS) {
147
			try {
148
				// Configure importer with last state
149
				$importer = self::$backend->GetImporter();
150
				$importer->Config($syncstate);
151
152
				// the messages from the PIM will be forwarded to the real importer
153
				$changesMem->SetDestinationImporter($importer);
154
155
				// Create SyncFolder object
156
				$folder = new SyncFolder();
157
				$folder->serverid = $serverid;
158
				$folder->parentid = $parentBackendId;
159
				if (isset($displayname)) {
160
					$folder->displayname = $displayname;
161
				}
162
				if (isset($type)) {
163
					$folder->type = $type;
164
				}
165
				// add the backendId to the SyncFolder object
166
				$folder->BackendId = $backendid;
167
168
				// process incoming change
169
				if (!$delete) {
170
					// when creating, $folder->serverid is false, and the returned id is already mapped by the backend
171
					$folder = $changesMem->ImportFolderChange($folder);
172
				}
173
				else {
174
					// delete folder
175
					$changesMem->ImportFolderDeletion($folder);
176
				}
177
			}
178
			catch (StatusException $stex) {
179
				$status = $stex->getCode();
180
			}
181
		}
182
183
		self::$encoder->startWBXML();
184
		if ($create) {
185
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERCREATE);
186
187
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
188
			self::$encoder->content($status);
189
			self::$encoder->endTag();
190
191
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
192
			self::$encoder->content($newsynckey);
193
			self::$encoder->endTag();
194
195
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID);
196
			self::$encoder->content($folder->serverid);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $folder does not seem to be defined for all execution paths leading up to this point.
Loading history...
197
			self::$encoder->endTag();
198
199
			self::$encoder->endTag();
200
		}
201
		elseif ($update) {
202
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERUPDATE);
203
204
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
205
			self::$encoder->content($status);
206
			self::$encoder->endTag();
207
208
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
209
			self::$encoder->content($newsynckey);
210
			self::$encoder->endTag();
211
212
			self::$encoder->endTag();
213
		}
214
		elseif ($delete) {
215
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERDELETE);
216
217
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
218
			self::$encoder->content($status);
219
			self::$encoder->endTag();
220
221
			self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
222
			self::$encoder->content($newsynckey);
223
			self::$encoder->endTag();
224
225
			self::$encoder->endTag();
226
		}
227
228
		self::$topCollector->AnnounceInformation(sprintf("Operation status %d", $status), true);
229
230
		// Save the sync state for the next time
231
		if (isset($importer)) {
232
			self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $importer->GetState());
233
234
			// update SPA & save it
235
			$spa->SetSyncKey($newsynckey);
236
			$spa->SetFolderId(false);
237
			self::$deviceManager->GetStateManager()->SetSynchedFolderState($spa);
238
239
			// invalidate all pingable flags
240
			SyncCollections::InvalidatePingableFlags();
241
		}
242
243
		return true;
244
	}
245
}
246