Test Failed
Push — master ( cd42b5...841446 )
by
unknown
16:44 queued 06:09
created

AppointmentItemModule::save()   D

Complexity

Conditions 24
Paths 108

Size

Total Lines 99
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 24
eloc 59
c 1
b 0
f 0
nc 108
nop 5
dl 0
loc 99
rs 4.1

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
	/**
4
	 * Appointment ItemModule
5
	 * Module which openes, creates, saves and deletes an item. It
6
	 * extends the Module class.
7
	 */
8
	class AppointmentItemModule extends ItemModule {
9
		/**
10
		 * Constructor.
11
		 *
12
		 * @param int   $id   unique id
13
		 * @param array $data list of all actions
14
		 */
15
		public function __construct($id, $data) {
16
			parent::__construct($id, $data);
17
18
			$this->properties = $GLOBALS['properties']->getAppointmentProperties();
0 ignored issues
show
Bug Best Practice introduced by
The property properties does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
19
20
			$this->plaintext = true;
21
			$this->skipCopyProperties = [
22
				$this->properties['goid'],
23
				$this->properties['goid2'],
24
				$this->properties['request_sent'],
25
				PR_OWNER_APPT_ID,
26
			];
27
		}
28
29
		public function open($store, $entryid, $action) {
30
			if ($store && $entryid) {
31
				$data = [];
32
33
				$message = $GLOBALS['operations']->openMessage($store, $entryid);
34
35
				if (empty($message)) {
36
					return;
37
				}
38
39
				// Open embedded message if requested
40
				$attachNum = !empty($action['attach_num']) ? $action['attach_num'] : false;
41
				if ($attachNum) {
42
					// get message props of sub message
43
					$parentMessage = $message;
44
					$message = $GLOBALS['operations']->openMessage($store, $entryid, $attachNum);
45
46
					if (empty($message)) {
47
						return;
48
					}
49
50
					$data['item'] = $GLOBALS['operations']->getEmbeddedMessageProps($store, $message, $this->properties, $parentMessage, $attachNum);
51
				}
52
				else {
53
					// add all standard properties from the series/normal message
54
					$data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $this->properties, $this->plaintext);
55
				}
56
57
				// if appointment is recurring then only we should get properties of occurrence if basedate is supplied
58
				if ($data['item']['props']['recurring'] === true) {
59
					if (!empty($action['basedate'])) {
60
						// check for occurrence/exception
61
						$basedate = $action['basedate'];
62
63
						$recur = new Recurrence($store, $message);
64
65
						$exceptionatt = $recur->getExceptionAttachment($basedate);
66
67
						// Single occurrences are never recurring
68
						$data['item']['props']['recurring'] = false;
69
70
						if ($exceptionatt) {
71
							// Existing exception (open existing item, which includes basedate)
72
							$exceptionattProps = mapi_getprops($exceptionatt, [PR_ATTACH_NUM]);
73
							$exception = mapi_attach_openobj($exceptionatt, 0);
74
75
							// overwrite properties with the ones from the exception
76
							$exceptionProps = $GLOBALS['operations']->getMessageProps($store, $exception, $this->properties, $this->plaintext);
77
78
							/*
79
							 * If recurring item has set reminder to true then
80
							 * all occurrences before the 'flagdueby' value(of recurring item)
81
							 * should not show that reminder is set.
82
							 */
83
							if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
84
								$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
85
86
								if ($flagDueByDay > $basedate) {
87
									$exceptionProps['props']['reminder'] = false;
88
								}
89
							}
90
91
							// The properties must be merged, if the recipients or attachments are present in the exception
92
							// then that list should be used. Otherwise the list from the series must be applied (this
93
							// corresponds with OL2007).
94
							// @FIXME getMessageProps should not return empty string if exception doesn't contain body
95
							// by this change we can handle a situation where user has set empty string in the body explicitly
96
							if (!empty($exceptionProps['props']['body']) || !empty($exceptionProps['props']['html_body'])) {
97
								if (!empty($exceptionProps['props']['body'])) {
98
									$data['item']['props']['body'] = $exceptionProps['props']['body'];
99
								}
100
101
								if (!empty($exceptionProps['props']['html_body'])) {
102
									$data['item']['props']['html_body'] = $exceptionProps['props']['html_body'];
103
								}
104
105
								$data['item']['props']['isHTML'] = $exceptionProps['props']['isHTML'];
106
							}
107
							// remove properties from $exceptionProps so array_merge will not overwrite it
108
							unset($exceptionProps['props']['html_body'], $exceptionProps['props']['body'], $exceptionProps['props']['isHTML']);
109
110
							$data['item']['props'] = array_merge($data['item']['props'], $exceptionProps['props']);
111
							if (isset($exceptionProps['recipients'])) {
112
								$data['item']['recipients'] = $exceptionProps['recipients'];
113
							}
114
115
							if (isset($exceptionProps['attachments'])) {
116
								$data['item']['attachments'] = $exceptionProps['attachments'];
117
							}
118
119
							// Make sure we are using the passed basedate and not something wrong in the opened item
120
							$data['item']['props']['basedate'] = $basedate;
121
							$data['item']['attach_num'] = [$exceptionattProps[PR_ATTACH_NUM]];
122
						}
123
						elseif ($recur->isDeleteException($basedate)) {
124
							// Exception is deleted, should not happen, but if it the case then give error
125
							$this->sendFeedback(
126
								false,
127
								[
128
									'type' => ERROR_ZARAFA,
129
									'info' => [
130
										'original_message' => _('Could not open occurrence.'),
131
										'display_message' => _('Could not open occurrence, specific occurrence is probably deleted.'),
132
									],
133
								]
134
							);
135
136
							return;
137
						}
138
						else {
139
							// opening an occurrence of a recurring series (same as normal open, but add basedate, startdate and enddate)
140
							$data['item']['props']['basedate'] = $basedate;
141
							$data['item']['props']['startdate'] = $recur->getOccurrenceStart($basedate);
142
							$data['item']['props']['duedate'] = $recur->getOccurrenceEnd($basedate);
143
							$data['item']['props']['commonstart'] = $data['item']['props']['startdate'];
144
							$data['item']['props']['commonend'] = $data['item']['props']['duedate'];
145
							unset($data['item']['props']['reminder_time']);
146
147
							/*
148
							 * If recurring item has set reminder to true then
149
							 * all occurrences before the 'flagdueby' value(of recurring item)
150
							 * should not show that reminder is set.
151
							 */
152
							if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $exceptionProps does not exist. Did you maybe mean $exception?
Loading history...
153
								$flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']);
154
155
								if ($flagDueByDay > $basedate) {
156
									$exceptionProps['props']['reminder'] = false;
157
								}
158
							}
159
						}
160
					}
161
					else {
162
						// Opening a recurring series, get the recurrence information
163
						$recur = new Recurrence($store, $message);
164
						$recurpattern = $recur->getRecurrence();
165
						$tz = $recur->tz; // no function to do this at the moment
166
167
						// Add the recurrence pattern to the data
168
						if (isset($recurpattern) && is_array($recurpattern)) {
0 ignored issues
show
introduced by
The condition is_array($recurpattern) is always false.
Loading history...
169
							$data['item']['props'] += $recurpattern;
170
						}
171
172
						// Add the timezone information to the data
173
						if (isset($tz) && is_array($tz)) {
0 ignored issues
show
introduced by
The condition is_array($tz) is always false.
Loading history...
174
							$data['item']['props'] += $tz;
175
						}
176
					}
177
				}
178
179
				// Send the data
180
				$this->addActionData('item', $data);
181
				$GLOBALS['bus']->addData($this->getResponseData());
182
			}
183
		}
184
185
		/**
186
		 * Function does customization of exception based on module data.
187
		 * like, here it will generate display message based on actionType
188
		 * for particular exception.
189
		 *
190
		 * @param object     $e             Exception object
191
		 * @param string     $actionType    the action type, sent by the client
192
		 * @param MAPIobject $store         store object of message
0 ignored issues
show
Bug introduced by
The type MAPIobject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
193
		 * @param string     $parententryid parent entryid of the message
194
		 * @param string     $entryid       entryid of the message
195
		 * @param array      $action        the action data, sent by the client
196
		 */
197
		public function handleException(&$e, $actionType = null, $store = null, $parententryid = null, $entryid = null, $action = null) {
198
			if (is_null($e->displayMessage)) {
199
				switch ($actionType) {
200
					case "save":
201
						if ($e->getCode() == MAPI_E_NO_ACCESS) {
202
							$message = mapi_msgstore_openentry($store, $entryid);
203
							$messageProps = mapi_getprops($message, [PR_MESSAGE_CLASS, PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID]);
204
							$messageClass = $messageProps[PR_MESSAGE_CLASS];
205
206
							$text = $messageClass !== "IPM.Appointment" ? _('a meeting request') : _('an appointment');
207
							$msg = _('You have insufficient privileges to move ' . $text . ' in this calendar. The calendar owner can set these using the \'permissions\'-tab of the folder properties (right click the calendar folder > properties > permissions)');
208
209
							$e->setDisplayMessage($msg);
210
							$e->setTitle(_('Insufficient privileges'));
211
212
							// Need this notification to refresh the calendar.
213
							$GLOBALS['bus']->notify(bin2hex($parententryid), TABLE_DELETE, $messageProps);
0 ignored issues
show
Bug introduced by
It seems like $parententryid can also be of type null; however, parameter $string of bin2hex() does only seem to accept string, 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

213
							$GLOBALS['bus']->notify(bin2hex(/** @scrutinizer ignore-type */ $parententryid), TABLE_DELETE, $messageProps);
Loading history...
214
						}
215
						break;
216
				}
217
			}
218
			parent::handleException($e, $actionType, $store, $parententryid, $entryid, $action);
219
		}
220
221
		/**
222
		 * Save the give appointment or meeting request to the calendar.
223
		 *
224
		 * @param mapistore $store         MAPI store of the message
0 ignored issues
show
Bug introduced by
The type mapistore was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
225
		 * @param string    $parententryid Parent entryid of the message (folder entryid, NOT message entryid)
226
		 * @param string    $entryid       entryid of the message
227
		 * @param array     $action        Action array containing json request
228
		 * @param string    $actionType    The action type which triggered this action
229
		 */
230
		public function save($store, $parententryid, $entryid, $action, $actionType = 'save') {
231
			$result = false;
232
233
			// Save appointment (saveAppointment takes care of creating/modifying exceptions to recurring
234
			// items if necessary)
235
			$messageProps = $GLOBALS['operations']->saveAppointment($store, $entryid, $parententryid, $action, $actionType, $this->directBookingMeetingRequest);
236
237
			// Notify the bus if the save was OK
238
			if ($messageProps && !(is_array($messageProps) && isset($messageProps['error'])) && !isset($messageProps['remindertimeerror'])) {
239
				$GLOBALS['bus']->notify(bin2hex($parententryid), TABLE_SAVE, $messageProps);
240
				$result = true;
241
			}
242
243
			$errorMsg = false;
244
			if (!$result && isset($messageProps['remindertimeerror']) && !$messageProps['remindertimeerror']) {
245
				$errorMsg = _('Cannot set a reminder to appear before the previous occurrence. Reset reminder to save the change');
246
			}
247
			elseif (isset($messageProps['isexceptionallowed']) && $messageProps['isexceptionallowed'] === false) {
248
				$errorMsg = _('Two occurrences cannot occur on the same day');
249
			}
250
			elseif (is_array($messageProps) && isset($messageProps['error'])) {
251
				switch ($messageProps['error']) {
252
					case 1:
253
						$errorMsg = sprintf(_('You marked \'%s\' as a resource. You cannot schedule a meeting with \'%s\' because you do not have the appropriate permissions for that account. Either enter the name as a required or optional attendee or talk to your administrator about giving you permission to schedule \'%s\'.'), $messageProps['displayname'], $messageProps['displayname'], $messageProps['displayname']);
254
						break;
255
256
					case 2:
257
						$errorMsg = sprintf(_('\'%s\' has declined your meeting because \'%s\' does not automatically accept meeting requests.'), $messageProps['displayname'], $messageProps['displayname']);
258
						break;
259
260
					case 3:
261
						$errorMsg = sprintf(_('\'%s\' has declined your meeting because it is recurring. You must book each meeting separately with this resource.'), $messageProps['displayname']);
262
						break;
263
264
					case 4:
265
						$errorMsg = sprintf(_('\'%s\' is already booked for this specified time. You must use another time or find another resource.'), $messageProps['displayname']);
266
						break;
267
268
					default:
269
						$errorMsg = _('Meeting was not scheduled.');
270
						break;
271
				}
272
			}
273
			else {
274
				// Recurring but non-existing exception (same as normal open, but add basedate, startdate and enddate)
275
				$data = [];
276
				if ($result) {
277
					$data = Conversion::mapMAPI2XML($this->properties, $messageProps);
278
279
					// Get recipient information from the saved appointment to update client side
280
					// according to the latest recipient related changes only if changes requested from client.
281
					$savedAppointment = $GLOBALS['operations']->openMessage($store, $messageProps[PR_ENTRYID]);
282
					if (!empty($action['recipients'])) {
283
						$recipients = $GLOBALS["operations"]->getRecipientsInfo($savedAppointment);
284
						if (!empty($recipients)) {
285
							$data["recipients"] = [
286
								"item" => $recipients,
287
							];
288
						}
289
					}
290
291
					// Get attachments information from the saved appointment to update client side
292
					// according to the latest attachments related changes only if changes requested from client.
293
					if (!empty($action['attachments'])) {
294
						$attachments = $GLOBALS["operations"]->getAttachmentsInfo($savedAppointment);
295
						if (!empty($attachments)) {
296
							$data["attachments"] = [
297
								"item" => $attachments,
298
							];
299
						}
300
					}
301
302
					$data['action_response'] = [
303
						'resources_booked' => $this->directBookingMeetingRequest,
304
					];
305
306
					if (isset($action['message_action'], $action['message_action']['paste'])) {
307
						$data['action_response']['resources_pasted'] = true;
308
					}
309
				}
310
				else {
311
					if (!empty($action['message_action']['send'])) {
312
						$errorMsg = _('Meeting could not be sent.');
313
					}
314
					else {
315
						$errorMsg = _('Meeting could not be saved.');
316
					}
317
				}
318
			}
319
320
			if ($errorMsg === false) {
321
				$this->addActionData('update', ['item' => $data]);
322
				$GLOBALS['bus']->addData($this->getResponseData());
323
			}
324
			else {
325
				$this->sendFeedback(false, [
326
					'type' => ERROR_ZARAFA,
327
					'info' => [
328
						'display_message' => $errorMsg,
329
					],
330
				]);
331
			}
332
		}
333
	}
334