Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

TaskRecurrence   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 389
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 190
dl 0
loc 389
rs 6
c 1
b 0
f 0
wmc 55

10 Methods

Rating   Name   Duplication   Size   Complexity  
F regenerateTask() 0 83 13
A __construct() 0 48 1
C moveToNextOccurrence() 0 56 12
A deleteOccurrence() 0 9 1
A setFirstOccurrence() 0 16 2
A processOccurrenceItem() 0 14 4
A markOccurrenceComplete() 0 12 3
A setRecurrence() 0 28 6
A getNextOccurrence() 0 17 5
B setReminder() 0 30 8

How to fix   Complexity   

Complex Class

Complex classes like TaskRecurrence 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.

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 TaskRecurrence, and based on these observations, apply Extract Interface, too.

1
<?php
2
	require_once(BASE_PATH . 'server/includes/mapi/class.baserecurrence.php');
3
4
	class TaskRecurrence extends BaseRecurrence
5
	{
6
		/**
7
		 * Timezone info which is always false for task
8
		 */
9
		var $tz = false;
10
11
		function __construct($store, $message)
12
		{
13
			$this->store = $store;
14
			$this->message = $message;
15
16
			$properties = array();
17
			$properties["entryid"] = PR_ENTRYID;
18
			$properties["parent_entryid"] = PR_PARENT_ENTRYID;
19
			$properties["icon_index"] = PR_ICON_INDEX;
20
			$properties["message_class"] = PR_MESSAGE_CLASS;
21
			$properties["message_flags"] = PR_MESSAGE_FLAGS;
22
			$properties["subject"] = PR_SUBJECT;
23
			$properties["importance"] = PR_IMPORTANCE;
24
			$properties["sensitivity"] = PR_SENSITIVITY;
25
			$properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME;
26
			$properties["status"] = "PT_LONG:PSETID_Task:0x8101";
27
			$properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102";
28
			$properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104";
29
			$properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105";
30
			$properties["reset_reminder"] = "PT_BOOLEAN:PSETID_Task:0x8107";
31
			$properties["dead_occurrence"] = "PT_BOOLEAN:PSETID_Task:0x8109";
32
			$properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f";
33
			$properties["recurring_data"] = "PT_BINARY:PSETID_Task:0x8116";
34
			$properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110";
35
			$properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111";
36
			$properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c";
37
			$properties["task_f_creator"] = "PT_BOOLEAN:PSETID_Task:0x811e";
38
			$properties["owner"] = "PT_STRING8:PSETID_Task:0x811f";
39
			$properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126";
40
41
			$properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
42
			$properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
43
			$properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
44
45
			$properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
46
			$properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
47
			$properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
48
			$properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
49
50
			$properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
51
			$properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
52
			$properties["commonassign"] = "PT_LONG:PSETID_Common:0x8518";
53
			$properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560";
54
			$properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510";
55
56
			$this->proptags = getPropIdsFromStrings($store, $properties);
57
58
			parent::__construct($store, $message, $properties);
0 ignored issues
show
Unused Code introduced by
The call to BaseRecurrence::__construct() has too many arguments starting with $properties. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

58
			parent::/** @scrutinizer ignore-call */ 
59
           __construct($store, $message, $properties);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
59
		}
60
61
		/**
62
		 * Function which saves recurrence and also regenerates task if necessary.
63
		 *@param array $recur new recurrence properties
64
		 *@return array of properties of regenerated task else false
65
		 */
66
		function setRecurrence(&$recur)
67
		{
68
			$this->recur = $recur;
0 ignored issues
show
Documentation Bug introduced by
It seems like $recur of type array is incompatible with the declared type recurrence of property $recur.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
69
			$this->action =& $recur;
0 ignored issues
show
Bug Best Practice introduced by
The property action does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
70
71
			if(!isset($this->recur["changed_occurrences"]))
72
				$this->recur["changed_occurrences"] = Array();
73
74
			if(!isset($this->recur["deleted_occurrences"]))
75
				$this->recur["deleted_occurrences"] = Array();
76
77
			if (!isset($this->recur['startocc'])) $this->recur['startocc'] = 0;
78
			if (!isset($this->recur['endocc'])) $this->recur['endocc'] = 0;
79
80
			// Save recurrence because we need proper startrecurrdate and endrecurrdate
81
			$this->saveRecurrence();
82
83
			// Update $this->recur with proper startrecurrdate and endrecurrdate updated after saving recurrence
84
			$msgProps = mapi_getprops($this->message, array($this->proptags['recurring_data']));
85
			$recurring_data = $this->parseRecurrence($msgProps[$this->proptags['recurring_data']]);
86
			foreach($recurring_data as $key => $value) {
87
				$this->recur[$key] = $value;
88
			}
89
90
			$this->setFirstOccurrence();
91
92
			// Let's see if next occurrence has to be generated
93
			return $this->moveToNextOccurrence();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->moveToNextOccurrence() returns the type boolean which is incompatible with the documented return type array.
Loading history...
94
		}
95
96
		/**
97
		 * Sets task object to first occurrence if startdate/duedate of task object is different from first occurrence
98
		 */
99
		function setFirstOccurrence()
100
		{
101
			// Check if it is already the first occurrence
102
			if($this->action['start'] == $this->recur["start"]){
103
				return;
104
			} else {
105
				$items = $this->getNextOccurrence();
106
107
				$props = array();
108
				$props[$this->proptags['startdate']] = $items[$this->proptags['startdate']];
109
				$props[$this->proptags['commonstart']] = $items[$this->proptags['startdate']];
110
111
				$props[$this->proptags['duedate']] = $items[$this->proptags['duedate']];
112
				$props[$this->proptags['commonend']] = $items[$this->proptags['duedate']];
113
114
				mapi_setprops($this->message, $props);
115
			}
116
		}
117
118
		/**
119
		 * Function which creates new task as current occurrence and moves the
120
		 * existing task to next occurrence.
121
		 *
122
		 *@param array $recur $action from client
123
		 *@return boolean if moving to next occurrence succeed then it returns
124
		 *		properties of either newly created task or existing task ELSE
125
		 *		false because that was last occurrence
126
		 */
127
		function moveToNextOccurrence()
128
		{
129
			$result = false;
130
			/**
131
			 * Every recurring task should have a 'duedate'. If a recurring task is created with no start/end date
132
			 * then we create first two occurrence separately and for first occurrence recurrence has ended.
133
			 */
134
			if ((empty($this->action['startdate']) && empty($this->action['duedate']))
135
				|| ($this->action['complete'] == 1) || (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence'])){
136
137
				$nextOccurrence = $this->getNextOccurrence();
138
				$result = mapi_getprops($this->message, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID));
139
140
				$props = array();
141
				if ($nextOccurrence) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nextOccurrence of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
142
					if (!isset($this->action['deleteOccurrence'])) {
143
						// Create current occurrence as separate task
144
						$result = $this->regenerateTask($this->action['complete']);
145
					}
146
147
					// Set reminder for next occurrence
148
					$this->setReminder($nextOccurrence);
149
150
					// Update properties for next occurrence
151
					$this->action['duedate'] = $props[$this->proptags['duedate']] = $nextOccurrence[$this->proptags['duedate']];
0 ignored issues
show
Bug Best Practice introduced by
The property action does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
152
					$this->action['commonend'] = $props[$this->proptags['commonend']] = $nextOccurrence[$this->proptags['duedate']];
153
154
					$this->action['startdate'] = $props[$this->proptags['startdate']] = $nextOccurrence[$this->proptags['startdate']];
155
					$this->action['commonstart'] = $props[$this->proptags['commonstart']] = $nextOccurrence[$this->proptags['startdate']];
156
157
					// If current task as been mark as 'Complete' then next occurrence should be incomplete.
158
					if (isset($this->action['complete']) && $this->action['complete'] == 1) {
159
						$this->action['status'] = $props[$this->proptags["status"]] = olTaskNotStarted;
160
						$this->action['complete'] = $props[$this->proptags["complete"]] = false;
161
						$this->action['percent_complete'] = $props[$this->proptags["percent_complete"]] = 0;
162
					}
163
164
					$props[$this->proptags["dead_occurrence"]] = false;
165
				} else {
166
					if (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence'])
167
						return false;
168
169
					// Didn't get next occurrence, probably this is the last one, so recurrence ends here
170
					$props[$this->proptags["dead_occurrence"]] = true;
171
					$props[$this->proptags["datecompleted"]] = $this->action['datecompleted'];
172
					$props[$this->proptags["task_f_creator"]] = true;
173
174
					//OL props
175
					$props[$this->proptags["side_effects"]] = 1296;
176
					$props[$this->proptags["icon_index"]] = 1280;
177
				}
178
179
				mapi_setprops($this->message, $props);
180
			}
181
182
			return $result;
183
		}
184
185
		/**
186
		 * Function which return properties of next occurrence
187
		 *@return array startdate/enddate of next occurrence
188
		 */
189
		function getNextOccurrence()
190
		{
191
			if ($this->recur) {
192
				$items = array();
0 ignored issues
show
Unused Code introduced by
The assignment to $items is dead and can be removed.
Loading history...
193
194
				//@TODO: fix start of range
195
				$start = isset($this->messageprops[$this->proptags["duedate"]]) ? $this->messageprops[$this->proptags["duedate"]] : $this->action['start'];
196
				$dayend = ($this->recur['term'] == 0x23) ? 0x7fffffff : $this->dayStartOf($this->recur["end"]);
197
198
				// Fix recur object
199
				$this->recur['startocc'] = 0;
200
				$this->recur['endocc'] = 0;
201
202
				// Retrieve next occurrence
203
				$items = $this->getItems($start, $dayend, 1);
0 ignored issues
show
Bug introduced by
It seems like $dayend can also be of type integer; however, parameter $end of BaseRecurrence::getItems() does only seem to accept date, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

203
				$items = $this->getItems($start, /** @scrutinizer ignore-type */ $dayend, 1);
Loading history...
204
205
				return !empty($items) ? $items[0] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! empty($items) ? $items[0] : false could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
206
			}
207
		}
208
209
		/**
210
		 * Function which clones current occurrence and sets appropriate properties.
211
		 * The original recurring item is moved to next occurrence.
212
		 *@param boolean $markComplete true if existing occurrence has to be mark complete else false.
213
		 */
214
		function regenerateTask($markComplete)
215
		{
216
			// Get all properties
217
			$taskItemProps = mapi_getprops($this->message);
218
219
			if (isset($this->action["subject"])) $taskItemProps[$this->proptags["subject"]] = $this->action["subject"];
220
			if (isset($this->action["importance"])) $taskItemProps[$this->proptags["importance"]] = $this->action["importance"];
221
			if (isset($this->action["startdate"])) {
222
				$taskItemProps[$this->proptags["startdate"]] = $this->action["startdate"];
223
				$taskItemProps[$this->proptags["commonstart"]] = $this->action["startdate"];
224
			}
225
			if (isset($this->action["duedate"])) {
226
				$taskItemProps[$this->proptags["duedate"]] = $this->action["duedate"];
227
				$taskItemProps[$this->proptags["commonend"]] = $this->action["duedate"];
228
			}
229
230
			$folder = mapi_msgstore_openentry($this->store, $taskItemProps[PR_PARENT_ENTRYID]);
231
			$newMessage = mapi_folder_createmessage($folder);
232
233
			$taskItemProps[$this->proptags["status"]] = $markComplete ? olTaskComplete : olTaskNotStarted;
234
			$taskItemProps[$this->proptags["complete"]] = $markComplete;
235
			$taskItemProps[$this->proptags["percent_complete"]] = $markComplete ? 1 : 0;
236
237
			// This occurrence has been marked as 'Complete' so disable reminder
238
			if ($markComplete) {
239
				$taskItemProps[$this->proptags["reset_reminder"]] = false;
240
				$taskItemProps[$this->proptags["reminder"]] = false;
241
				$taskItemProps[$this->proptags["datecompleted"]] = $this->action["datecompleted"];
242
243
				unset($this->action[$this->proptags['datecompleted']]);
244
			}
245
246
			// Recurrence ends for this item
247
			$taskItemProps[$this->proptags["dead_occurrence"]] = true;
248
			$taskItemProps[$this->proptags["task_f_creator"]] = true;
249
250
			//OL props
251
			$taskItemProps[$this->proptags["side_effects"]] = 1296;
252
			$taskItemProps[$this->proptags["icon_index"]] = 1280;
253
254
			// Copy recipients
255
			$recipienttable = mapi_message_getrecipienttable($this->message);
256
			$recipients = mapi_table_queryallrows($recipienttable, array(PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_ENTRYID, PR_RECIPIENT_TYPE, PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO, PR_RECIPIENT_DISPLAY_NAME, PR_ADDRTYPE, PR_DISPLAY_TYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TRACKSTATUS_TIME, PR_RECIPIENT_FLAGS, PR_ROWID));
257
258
			$copy_to_recipientTable = mapi_message_getrecipienttable($newMessage);
259
			$copy_to_recipientRows = mapi_table_queryallrows($copy_to_recipientTable, array(PR_ROWID));
260
			foreach($copy_to_recipientRows as $recipient) {
261
				mapi_message_modifyrecipients($newMessage, MODRECIP_REMOVE, array($recipient));
262
			}
263
			mapi_message_modifyrecipients($newMessage, MODRECIP_ADD, $recipients);
264
265
			// Copy attachments
266
			$attachmentTable = mapi_message_getattachmenttable($this->message);
267
			if($attachmentTable) {
268
				$attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
269
270
				foreach($attachments as $attach_props){
271
					$attach_old = mapi_message_openattach($this->message, (int) $attach_props[PR_ATTACH_NUM]);
272
					$attach_newResourceMsg = mapi_message_createattach($newMessage);
273
274
					mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0);
275
					mapi_savechanges($attach_newResourceMsg);
276
				}
277
			}
278
279
			mapi_setprops($newMessage, $taskItemProps);
280
			mapi_savechanges($newMessage);
281
282
			// Update body of original message
283
			$msgbody = mapi_message_openproperty($this->message, PR_BODY);
284
			$msgbody = trim($msgbody, "\0");
285
			$separator = "------------\r\n";
286
287
			if (!empty($msgbody) && strrpos($msgbody, $separator) === false) {
288
				$msgbody = $separator . $msgbody;
289
				$stream = mapi_openproperty($this->message, PR_BODY, IID_IStream, 0, 0);
290
				mapi_stream_setsize($stream, strlen($msgbody));
291
				mapi_stream_write($stream, $msgbody);
292
				mapi_stream_commit($stream);
293
			}
294
295
			// We need these properties to notify client
296
			return mapi_getprops($newMessage, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID));
297
		}
298
299
		/**
300
		 * processOccurrenceItem, adds an item to a list of occurrences, but only if the
301
		 * resulting occurrence starts or ends in the interval <$start, $end>
302
		 * @param array $items reference to the array to be added to
303
		 * @param date $start start of timeframe in GMT TIME
304
		 * @param date $end end of timeframe in GMT TIME
305
		 * @param date $basedate (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE
306
		 */
307
		function processOccurrenceItem(&$items, $start, $end, $now)
0 ignored issues
show
Unused Code introduced by
The parameter $end is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

307
		function processOccurrenceItem(&$items, $start, /** @scrutinizer ignore-unused */ $end, $now)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
308
		{
309
			if ($now > $start) {
310
				$newItem = array();
311
				$newItem[$this->proptags['startdate']] = $now;
312
313
				// If startdate and enddate are set on task, then slide enddate according to duration
314
				if (isset($this->messageprops[$this->proptags["startdate"]]) && isset($this->messageprops[$this->proptags["duedate"]])) {
315
					$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']] + ($this->messageprops[$this->proptags["duedate"]] - $this->messageprops[$this->proptags["startdate"]]);
316
				} else {
317
					$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']];
318
				}
319
320
				$items[] = $newItem;
321
			}
322
		}
323
324
		/**
325
		 * Function which marks existing occurrence to 'Complete'
326
		 *@param array $recur array action from client
327
		 *@return array of properties of regenerated task else false
328
		 */
329
		function markOccurrenceComplete(&$recur)
330
		{
331
			// Fix timezone object
332
			$this->tz = false;
333
			$this->action =& $recur;
0 ignored issues
show
Bug Best Practice introduced by
The property action does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
334
			$dead_occurrence = isset($this->messageprops[$this->proptags['dead_occurrence']]) ? $this->messageprops[$this->proptags['dead_occurrence']] : false;
335
336
			if (!$dead_occurrence) {
337
				return $this->moveToNextOccurrence();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->moveToNextOccurrence() returns the type boolean which is incompatible with the documented return type array.
Loading history...
338
			}
339
340
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
341
		}
342
343
		/**
344
		 * Function which sets reminder on recurring task after existing occurrence has been deleted or marked complete.
345
		 *@param array $nextOccurrence properties of next occurrence
346
		 */
347
		function setReminder($nextOccurrence)
348
		{
349
			$props = array();
350
			if ($nextOccurrence) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nextOccurrence of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
351
				// Check if reminder is reset. Default is 'false'
352
				$reset_reminder = isset($this->messageprops[$this->proptags['reset_reminder']]) ? $this->messageprops[$this->proptags['reset_reminder']] : false;
353
				$reminder = $this->messageprops[$this->proptags['reminder']];
354
355
				// Either reminder was already set OR reminder was set but was dismissed bty user
356
				if ($reminder || $reset_reminder) {
357
					// Reminder can be set at any time either before or after the duedate, so get duration between the reminder time and duedate
358
					$reminder_time = isset($this->messageprops[$this->proptags['reminder_time']]) ? $this->messageprops[$this->proptags['reminder_time']] : 0;
359
					$reminder_difference = isset($this->messageprops[$this->proptags['duedate']]) ? $this->messageprops[$this->proptags['duedate']] : 0;
360
					$reminder_difference = $reminder_difference - $reminder_time;
361
362
					// Apply duration to next calculated duedate
363
					$next_reminder_time = $nextOccurrence[$this->proptags['duedate']] - $reminder_difference;
364
365
					$props[$this->proptags['reminder_time']] = $next_reminder_time;
366
					$props[$this->proptags['flagdueby']] = $next_reminder_time;
367
					$this->action['reminder'] = $props[$this->proptags['reminder']] = true;
0 ignored issues
show
Bug Best Practice introduced by
The property action does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
368
				}
369
			} else {
370
				// Didn't get next occurrence, probably this is the last occurrence
371
				$props[$this->proptags['reminder']] = false;
372
				$props[$this->proptags['reset_reminder']] = false;
373
			}
374
375
			if (!empty($props))
376
				mapi_setprops($this->message, $props);
377
		}
378
379
		/**
380
		 * Function which recurring task to next occurrence.
381
		 * It simply doesn't regenerate task
382
		 @param array $action
383
		 */
384
		function deleteOccurrence($action)
385
		{
386
			$this->tz = false;
387
			$this->action = $action;
0 ignored issues
show
Bug Best Practice introduced by
The property action does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
388
			$result = $this->moveToNextOccurrence();
389
390
			mapi_savechanges($this->message);
391
392
			return $result;
393
		}
394
	}
395
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
396