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

AddressbookItemModule   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 420
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 173
dl 0
loc 420
rs 8.64
c 0
b 0
f 0
wmc 47

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getProxyAddressesDetails() 0 15 4
A getOwnerDetails() 0 11 2
A getManagerDetails() 0 11 2
A getMembersDetails() 0 20 3
A getBusinessPhoneNumbers() 0 15 4
A getDirectReportsDetails() 0 24 4
A __construct() 0 7 1
A getMemberOfDetails() 0 16 3
F open() 0 189 20
A getHomePhoneNumbers() 0 15 4

How to fix   Complexity   

Complex Class

Complex classes like AddressbookItemModule 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 AddressbookItemModule, and based on these observations, apply Extract Interface, too.

1
<?php
2
	/**
3
	 * Read Mail ItemModule
4
	 */
5
	class AddressbookItemModule extends ItemModule
6
	{
7
8
		/**
9
		 * Constructor
10
		 * @param int $id unique id.
11
		 * @param array $data list of all actions.
12
		 */
13
		function __construct($id, $data)
14
		{
15
			$this->userDetailProperties = $GLOBALS["properties"]->getAddressBookItemMailuserProperties();
0 ignored issues
show
Bug Best Practice introduced by
The property userDetailProperties does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
16
			$this->abObjectDetailProperties = $GLOBALS["properties"]->getAddressBookItemABObjectProperties();
0 ignored issues
show
Bug Best Practice introduced by
The property abObjectDetailProperties does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
17
			$this->groupDetailProperties = $GLOBALS["properties"]->getAddressBookItemDistlistProperties();
0 ignored issues
show
Bug Best Practice introduced by
The property groupDetailProperties does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
18
19
			parent::__construct($id, $data);
20
		}
21
22
		/**
23
		 * Function which opens an item.
24
		 * @param object $store MAPI Message Store Object
25
		 * @param string $entryid entryid of the message
26
		 * @param array $action the action data, sent by the client
27
		 * @return boolean true on success or false on failure
28
		 */
29
		function open($store, $entryid, $action)
30
		{
31
			if($entryid) {
32
				$data = array();
33
34
				try {
35
					$abentry = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(false, true), $entryid);
36
				} catch (MAPIException $e) {
37
					// If the item not found in addressbook, it might be possible that
38
					// this particular item was added by setup-contact-provider mechanism.
39
					// Let us try to get that particular contact item in respective user store.
40
					// @Fixme: After implementation of KC-350 this extra handling can be removed.
41
					if ($e->getCode() == MAPI_E_NOT_FOUND || $e->getCode() == MAPI_E_INVALID_PARAMETER) {
42
						$hexEntryid = bin2hex($entryid);
43
						// Remove Address-Book-Provider prefix from the entryid
44
						$externalEntryid = $GLOBALS["entryid"]->unwrapABEntryIdObj($hexEntryid);
45
						// Check if it's a contact from the user's contacts folder
46
						$contactItem = $GLOBALS['operations']->openMessage($GLOBALS['mapisession']->getDefaultMessageStore(), hex2bin($externalEntryid));
47
48
						if ($contactItem === false) {
49
							// Retrieve user store entryid to which this external item belongs
50
							$userStore = $GLOBALS['operations']->getOtherStoreFromEntryid($externalEntryid);
51
52
							// If userStore not found it means user is not exists in address book
53
							if($userStore === false) {
54
								$msg = "The contact \"%s\" could not be displayed because it could not be retrieved or has been deleted";
55
56
								error_log(sprintf($msg, $action["message_action"]["username"]));
57
58
								$e->setTitle(_('Contact not found'));
59
								$e->setDisplayMessage(_("Contact information could not be displayed because the server had trouble retrieving the information.") .
60
								_("Please contact your system administrator if the problem persists."));
61
								throw $e;
62
								return false;
0 ignored issues
show
Unused Code introduced by
return false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
63
							}
64
65
							$e->setHandled();
66
							$contactItem = $GLOBALS['operations']->openMessage($userStore, hex2bin($externalEntryid));
67
						}
68
						
69
70
						if ($contactItem != false) {
71
							// Get necessary property from respective contact item
72
							$contactItemProps = mapi_getprops($contactItem, Array(PR_GIVEN_NAME, PR_DISPLAY_NAME, PR_TITLE, PR_COMPANY_NAME));
73
74
							// Use the data retrieved from contact item to prepare response
75
							// as similar as it seems like an addressbook item.
76
							$data['props'] = array (
77
								'object_type' => MAPI_MAILUSER,
78
								'given_name' => $contactItemProps[PR_GIVEN_NAME],
79
								'display_name' => $contactItemProps[PR_DISPLAY_NAME],
80
								'title' => $contactItemProps[PR_TITLE],
81
								'company_name' => $contactItemProps[PR_COMPANY_NAME]
82
							);
83
							$data['entryid'] = $hexEntryid;
84
85
							$this->addActionData("item", $data);
86
							$GLOBALS["bus"]->addData($this->getResponseData());
87
							return;
88
						}
89
					}
90
				}
91
92
				if(mapi_last_hresult() == NOERROR && $abentry){
93
					$objecttypeprop = mapi_getprops($abentry, Array(PR_OBJECT_TYPE));
94
95
					if(isset($objecttypeprop[PR_OBJECT_TYPE])){
96
						// Get the properties for a MAILUSER object and process those MAILUSER specific props that require some more actions
97
						if($objecttypeprop[PR_OBJECT_TYPE] == MAPI_MAILUSER){
98
							$messageprops = mapi_getprops($abentry, $this->userDetailProperties);
99
100
							$props = Conversion::mapMAPI2XML($this->userDetailProperties, $messageprops);
101
102
							if(isset($messageprops[PR_EMS_AB_THUMBNAIL_PHOTO])){
103
								$props['props']['ems_ab_thumbnail_photo'] = $GLOBALS['operations']->compressedImage($messageprops[PR_EMS_AB_THUMBNAIL_PHOTO]);
104
							}
105
106
							// Get the properties of the manager
107
							$managerProps = $this->getManagerDetails($messageprops);
108
							if($managerProps!==false){
0 ignored issues
show
introduced by
The condition $managerProps !== false is always true.
Loading history...
109
								$props['ems_ab_manager'] = array(
110
									'item' => $managerProps
111
								);
112
							}
113
114
							$homePhoneNumbers = $this->getHomePhoneNumbers($messageprops);
115
							if (!empty($homePhoneNumbers)){
116
								// Add the list of home2_telephone_number_mv in the correct format to $props list to be send to the client
117
								$props['home2_telephone_numbers'] = array(
118
									'item' => $homePhoneNumbers
119
								);
120
							}
121
122
							$businessPhoneNumbers = $this->getBusinessPhoneNumbers($messageprops);
123
							if (!empty($businessPhoneNumbers)){
124
								// Add the list of business2_telephone_number_mv in the correct format to $props list to be send to the client
125
								$props['business2_telephone_numbers'] = array(
126
									'item' => $businessPhoneNumbers
127
								);
128
							}
129
130
							// Get the properties of the "direct reports"
131
							$directReportsList = $this->getDirectReportsDetails($messageprops);
132
							if(!empty($directReportsList)){
133
								// Add the list of proxy_addresses in the correct format to the $props list to be send to the client.
134
								$props['ems_ab_reports'] = array(
135
									'item' => $directReportsList
136
								);
137
							}
138
139
						// Get the properties for a DISTLIST object and process those DISTLIST specific props that require some more actions
140
						} else {
141
							$messageprops = mapi_getprops($abentry, $this->groupDetailProperties);
142
							$props = Conversion::mapMAPI2XML($this->groupDetailProperties, $messageprops);
143
144
							// Get the properties of the owner
145
							$ownerProps = $this->getOwnerDetails($messageprops);
146
							if($ownerProps!==false){
0 ignored issues
show
introduced by
The condition $ownerProps !== false is always true.
Loading history...
147
								// We can use the same properties as we use for the manager in a MAILUSER
148
								$props['ems_ab_owner'] = array(
149
									'item' => $ownerProps
150
								);
151
							}
152
153
							// Get the list of members for this DISTLSIT
154
							$props['members'] = array(
155
								'item' => $this->getMembersDetails($abentry)
156
							);
157
						}
158
159
						// Get the proxy addresses list, this property exists in both MAILUSER and DISTLIST
160
						$proxyAddresses = $this->getProxyAddressesDetails($messageprops);
161
						// Remove the MV-flagged property
162
						if(!empty($proxyAddresses)){
163
							// Add the list of proxy_addresses in the correct format to the $props list to be send to the client.
164
							$props['ems_ab_proxy_addresses'] = array(
165
								'item' => $proxyAddresses
166
							);
167
						}
168
169
						// Get the properties of the group membership, this property exists in both MAILUSER and DISTLIST
170
						$memberOfList = $this->getMemberOfDetails($messageprops);
171
						if(!empty($memberOfList)){
172
							// Add the list of proxy_addresses in the correct format to the $props list to be send to the client.
173
							$props['ems_ab_is_member_of_dl'] = array(
174
								'item' => $memberOfList
175
							);
176
						}
177
178
						// Remove the MV-flagged properties and also its single valued counterpart
179
						unset($props['props']['ems_ab_is_member_of_dl']);
180
						unset($props['props']['business2_telephone_number_mv']);
181
						unset($props['props']['business2_telephone_number']);
182
						unset($props['props']['home2_telephone_number_mv']);
183
						unset($props['props']['home2_telephone_number']);
184
						unset($props['props']['ems_ab_proxy_addresses_mv']);
185
						unset($props['props']['ems_ab_proxy_addresses']);
186
						unset($props['props']['ems_ab_reports_mv']);
187
						unset($props['props']['ems_ab_reports']);
188
						unset($props['props']['ems_ab_owner']);
189
						unset($props['props']['ems_ab_manager']);
190
191
						// Allowing to hook in and add more properties
192
						$GLOBALS['PluginManager']->triggerHook("server.module.addressbookitemmodule.open.props", array(
193
							'moduleObject' =>& $this,
194
							'abentry' => $abentry,
195
							'object_type' => $objecttypeprop[PR_OBJECT_TYPE],
196
							'messageprops' => $messageprops,
197
							'props' =>& $props
198
						));
199
200
						$data["item"] = $props;
201
						$this->addActionData("item", $data);
202
					} else {
203
						// Handling error: not able to handle this type of object
204
						$data["error"] = array();
205
						$data["error"]["message"] = _("Could not handle this type of object.");
206
						$this->addActionData("error", $data);
207
					}
208
				} else {
209
					// Handle not being able to open the object
210
					$data["error"] = array();
211
					$data["error"]["hresult"] = mapi_last_hresult();
212
					$data["error"]["hresult_name"] = get_mapi_error_name(mapi_last_hresult());
213
					$data["error"]["message"] = _("Could not open this object.");
214
					$this->addActionData("error", $data);
215
				}
216
217
				$GLOBALS["bus"]->addData($this->getResponseData());
218
			}
219
		}
220
221
		/**
222
		 * Get Business Telephone numbers in the messageprops array when it is set in the
223
		 * PR_HOME2_TELEPHONE_NUMBER_MV. This property is poorly documented and in Outlook it checks
224
		 * the property with and without the MV flag. The one without a MV flag can contain only one
225
		 * entry and the one with MV flag can contain a list. It then merges both into one list.
226
		 * This function has the same behavior and sets the list in the $messageprops.
227
		 * @param $messageprops Array Details properties of an user entry.
228
		 * @return Array List of telephone numbers
229
		 */
230
		function getHomePhoneNumbers($messageprops)
231
		{
232
			$list = Array();
233
			if (isset($messageprops[$this->userDetailProperties['home2_telephone_number']])){
234
				$list[] = $messageprops[$this->userDetailProperties['home2_telephone_number']];
235
			}
236
			if(isset($messageprops[$this->userDetailProperties['home2_telephone_number_mv']])){
237
				$list = array_merge($list, $messageprops[$this->userDetailProperties['home2_telephone_number_mv']]);
238
			}
239
240
			$returnList = Array();
241
			for($i = 0, $len = count($list); $i < $len; $i++) {
242
				array_push($returnList, Array('number' => $list[$i]));
243
			}
244
			return $returnList;
245
		}
246
247
		/**
248
		 * Get Business Telephone numbers in the messageprops array when it is set in the
249
		 * PR_BUSINESS2_TELEPHONE_NUMBER_MV. This property is poorly documented and in Outlook it checks
250
		 * the property with and without the MV flag. The one without a MV flag can contain only one
251
		 * entry and the one with MV flag can contain a list. It then merges both into one list.
252
		 * This function has the same behavior and sets the list in the $messageprops.
253
		 * @param $messageprops Array Details properties of an user entry.
254
		 * @return Array List of telephone numbers
255
		 */
256
		function getBusinessPhoneNumbers($messageprops)
257
		{
258
			$list = Array();
259
			if (isset($messageprops[$this->userDetailProperties['business2_telephone_number']])){
260
				$list[] = $messageprops[$this->userDetailProperties['business2_telephone_number']];
261
			}
262
			if(isset($messageprops[$this->userDetailProperties['business2_telephone_number_mv']])){
263
				$list = array_merge($list, $messageprops[$this->userDetailProperties['business2_telephone_number_mv']]);
264
			}
265
266
			$returnList = Array();
267
			for($i = 0, $len = count($list); $i < $len; $i++) {
268
				array_push($returnList, Array('number' => $list[$i]));
269
			}
270
			return $returnList;
271
		}
272
273
		/**
274
		 * Get Proxy Addresses in the messageprops array when it is set in the
275
		 * PR_EMS_AB_PROXY_ADDRESSES. This property is poorly documented and in Outlook it checks
276
		 * the property with and without the MV flag. The one without a MV flag can contain only one
277
		 * entry and the one with MV flag can contain a list. It then merges both into one list.
278
		 * This function has the same behavior and sets the list in the $messageprops.
279
		 * @param $messageprops Array Details properties of an user entry.
280
		 * @return Array List of addresses
281
		 */
282
		function getProxyAddressesDetails($messageprops)
283
		{
284
			$list = Array();
285
			if(isset($messageprops[$this->userDetailProperties['ems_ab_proxy_addresses']])){
286
				$list[] = $messageprops[$this->userDetailProperties['ems_ab_proxy_addresses']];
287
			}
288
			if(isset($messageprops[$this->userDetailProperties['ems_ab_proxy_addresses_mv']])){
289
				$list = array_merge($list, $messageprops[$this->userDetailProperties['ems_ab_proxy_addresses_mv']]);
290
			}
291
292
			$returnList = Array();
293
			for($i = 0, $len = count($list); $i < $len; $i++) {
294
				array_push($returnList, Array('address' => $list[$i]));
295
			}
296
			return $returnList;
297
		}
298
299
		/**
300
		 * Get the information of the manager from the GAB details of a MAPI_MAILUSER. Will use the
301
		 * entryid to get the properties. If no entryid if found false is returned.
302
		 * @param $messageprops Array Details properties of an user entry.
303
		 * @return Boolean|Array List of properties or false if no manager is set
304
		 */
305
		function getManagerDetails($messageprops)
306
		{
307
			if(isset($messageprops[$this->userDetailProperties['ems_ab_manager']])){
308
				$entryidMananager = $messageprops[$this->userDetailProperties['ems_ab_manager']];
309
310
				$managerEntry = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(), $entryidMananager);
311
				$managerProps = mapi_getprops($managerEntry, $this->abObjectDetailProperties);
312
313
				return Conversion::mapMAPI2XML($this->abObjectDetailProperties, $managerProps);
314
			}
315
			return false;
316
		}
317
318
		/**
319
		 * Get the list of users that have been set in the PR_EMS_AB_REPORTS property in the
320
		 * $messageprops array. This property is poorly documented and in Outlook it checks
321
		 * the property with and without the MV flag. The one without a MV flag can contain only one
322
		 * entry and the one with MV flag can contain a list. It then merges both into one list.
323
		 * This function has the same behavior and sets the list in the $messageprops.
324
		 * @param $messageprops Array Details properties of an user entry.
325
		 * @return Boolean|Array List of properties or false if no manager is set
326
		 */
327
		function getDirectReportsDetails($messageprops)
328
		{
329
			/*
330
			 * Get the entryIds from the PR_EMS_AB_REPORTS property (with and without MV flag as a
331
			 * fallback) and put the entryIds in a list.
332
			 */
333
			$entryids = Array();
334
			if(isset($messageprops[$this->userDetailProperties['ems_ab_reports']])){
335
				$entryids[] = $messageprops[$this->userDetailProperties['ems_ab_reports']];
336
			}
337
			if(isset($messageprops[$this->userDetailProperties['ems_ab_reports_mv']])){
338
				$entryids = array_merge($entryids, $messageprops[$this->userDetailProperties['ems_ab_reports_mv']]);
339
			}
340
341
			$result = Array();
342
			// Convert the entryIds in an array of properties of the AB entryies
343
			for($i = 0, $len = count($entryids); $i < $len; $i++){
344
				// Get the properties from the AB entry
345
				$entry = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(), $entryids[$i]);
346
				$props = mapi_getprops($entry, $this->abObjectDetailProperties);
347
				// Convert the properties for each entry and put it in an array
348
				$result[] = Conversion::mapMAPI2XML($this->abObjectDetailProperties, $props);
349
			}
350
			return $result;
351
		}
352
353
		/**
354
		 * Get the list of users that have been set in the PR_EMS_AB_MEMBER_OF_DL property in the
355
		 * $messageprops array. This property is poorly documented and in Outlook it checks
356
		 * the property with and without the MV flag. The one without a MV flag can contain only one
357
		 * entry and the one with MV flag can contain a list. It then merges both into one list.
358
		 * This function has the same behavior and sets the list in the $messageprops.
359
		 * @param $messageprops Array Details properties of an user entry.
360
		 * @return Boolean|Array List of properties or false if no manager is set
361
		 */
362
		function getMemberOfDetails($messageprops)
363
		{
364
			$result = Array();
365
			// Get the properties of the group membership
366
			if(isset($messageprops[$this->userDetailProperties['ems_ab_is_member_of_dl']])){
367
				$entryids = $messageprops[$this->userDetailProperties['ems_ab_is_member_of_dl']];
368
				// Get the properties from every entryid in the memberOf list
369
				for($i = 0, $len = count($entryids); $i < $len; $i++){
370
					// Get the properties from the AB entry
371
					$entry = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(), $entryids[$i]);
372
					$props = mapi_getprops($entry, $this->abObjectDetailProperties);
373
					// Convert the properties for each entry and put it in an array
374
					$result[] = Conversion::mapMAPI2XML($this->abObjectDetailProperties, $props);
375
				}
376
			}
377
			return $result;
378
		}
379
380
		/**
381
		 * Get the information of the owner from the GAB details of a MAPI_DISTLIST. Will use the
382
		 * entryid to get the properties. If no entryid if found false is returned.
383
		 * @param $messageprops Array Details properties of an distlist entry.
384
		 * @return Boolean|Array List of properties or false if no owner is set
385
		 */
386
		function getOwnerDetails($messageprops)
387
		{
388
			if(isset($messageprops[$this->groupDetailProperties['ems_ab_owner']])){
389
				$entryidOwner = $messageprops[$this->groupDetailProperties['ems_ab_owner']];
390
391
				$ownerEntry = mapi_ab_openentry($GLOBALS["mapisession"]->getAddressbook(), $entryidOwner);
392
				$ownerProps = mapi_getprops($ownerEntry, $this->abObjectDetailProperties);
393
394
				return Conversion::mapMAPI2XML($this->abObjectDetailProperties, $ownerProps);
395
			}
396
			return false;
397
		}
398
399
		/**
400
		 * Get the information of the members from the GAB details of a MAPI_DISTLIST. The
401
		 * information can be found in the contentstable of the AB entry opened by the user.
402
		 * @param $abentry Resource Reference to the user-opened AB entry
403
		 * @return Boolean|Array List of members
404
		 */
405
		function getMembersDetails($abentry)
406
		{
407
			$result = Array();
408
409
			$table = mapi_folder_getcontentstable($abentry, MAPI_DEFERRED_ERRORS);
410
411
			/*
412
			 * To prevent loading a huge list that the browser cannot handle, it is possible to
413
			 * limit the maximum number of shown items. Note that when the table doesn't
414
			 * contain the requested number of rows, it will not give any errors and simply
415
			 * return what is available.
416
			 * When the limit is 0 or below, then no limit is applied and we use 0x7fffffff
417
			 * to indicate we want to have all rows from the table.
418
			 */
419
			$rows = mapi_table_queryrows($table, $this->abObjectDetailProperties, 0, (ABITEMDETAILS_MAX_NUM_DISTLIST_MEMBERS > 0) ? ABITEMDETAILS_MAX_NUM_DISTLIST_MEMBERS : 0x7fffffff);
420
			for($i = 0, $len = count($rows); $i < $len; $i++){
421
				$result[] = Conversion::mapMAPI2XML($this->abObjectDetailProperties, $rows[$i]);
422
			}
423
424
			return $result;
425
		}
426
427
	}
428
?>
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...
429