Total Complexity | 83 |
Total Lines | 536 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 1 | Features | 0 |
Complex classes like mail_acl 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 mail_acl, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
68 | class mail_acl |
||
69 | { |
||
70 | /** |
||
71 | * Methods callable via menuaction |
||
72 | * |
||
73 | * @var array |
||
74 | */ |
||
75 | var $public_functions = array( |
||
76 | 'edit' => True, |
||
77 | ); |
||
78 | |||
79 | /** |
||
80 | * static used define abbreviations for common access rights |
||
81 | * |
||
82 | * @array |
||
83 | * |
||
84 | */ |
||
85 | var $aclRightsAbbrvs = array( |
||
86 | 'lrs' => array('label'=>'readable','title'=>'Allows a user to read the contents of the mailbox.'), |
||
87 | 'lprs' => array('label'=>'post','title'=>'Allows a user to read the mailbox and post to it through the delivery system by sending mail to the submission address of the mailbox.'), |
||
88 | 'ilprs' => array('label'=>'append','title'=>'Allows a user to read the mailbox and append messages to it, either via IMAP or through the delivery system.'), |
||
89 | 'ilprsw' => array('label'=>'write','title'=>'Allows a user to read and write the maibox, post to it, append messages to it.'), |
||
90 | 'eilprswtk' => array('label'=>'write & delete','title'=>'Allows a user to read, write and create folders and mails, post to it, append messages to it and delete messages.'), |
||
91 | 'aeiklprstwx'=> array('label'=>'all','title'=>'The user has all possible rights on the mailbox. This is usually granted to users only on the mailboxes they own.'), |
||
92 | 'custom' => array('label'=>'custom','title'=>'User defined combination of rights for the ACL'), |
||
93 | ); |
||
94 | |||
95 | /** |
||
96 | * imap object instantiated in constructor for account to edit |
||
97 | * |
||
98 | * @var Mail\Imap |
||
99 | */ |
||
100 | var $imap; |
||
101 | |||
102 | /** |
||
103 | * |
||
104 | * @var mail_account |
||
105 | */ |
||
106 | var $current_account; |
||
107 | |||
108 | /** |
||
109 | * Edit folder ACLs of account(s) |
||
110 | * |
||
111 | * @param array $content = null |
||
112 | * @param string $msg = '' |
||
113 | * |
||
114 | */ |
||
115 | function edit(array $content=null ,$msg='') |
||
116 | { |
||
117 | $tmpl = new Etemplate('mail.acl'); |
||
118 | if (!is_array($content)) |
||
119 | { |
||
120 | $acc_id = $_GET['acc_id']?$_GET['acc_id']:$GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID']; |
||
121 | if (isset($_GET['account_id']) && !isset($GLOBALS['egw_info']['user']['apps']['admin'])) |
||
122 | { |
||
123 | Framework::window_close(lang('Permission denied')); |
||
124 | } |
||
125 | $account_id = $_GET['account_id']; |
||
126 | } |
||
127 | else |
||
128 | { |
||
129 | $acc_id = $content['acc_id']; |
||
130 | $account_id = $content['account_id']; |
||
131 | } |
||
132 | $account = Mail\Account::read($acc_id, $account_id); |
||
133 | $this->imap = $account->imapServer(isset($account_id) ? (int)$account_id : false); |
||
134 | |||
135 | $mailbox = $_GET['mailbox']? base64_decode($_GET['mailbox']): self::_extract_mailbox($content['mailbox'], $acc_id); |
||
136 | if (empty($mailbox)) |
||
137 | { |
||
138 | $mailbox = $this->imap->isAdminConnection ? $this->imap->getUserMailboxString($account_id) : 'INBOX'; |
||
139 | } |
||
140 | if (!$this->imap->isAdminConnection) |
||
141 | { |
||
142 | $tmpl->setElementAttribute('mailbox', 'autocomplete_url', 'mail.mail_compose.ajax_searchFolder'); |
||
143 | $tmpl->setElementAttribute('mailbox', 'autocomplete_params', array('mailaccount' => $acc_id)); |
||
144 | } |
||
145 | else |
||
146 | { |
||
147 | //Todo: Implement autocomplete_url function with admin stuffs consideration |
||
148 | } |
||
149 | // Unset the content if folder is changed, in order to read acl rights for new selected folder |
||
150 | if (!is_array($content['button']) && self::_extract_mailbox($content['mailbox'], $acc_id) && !is_array($content['grid']['delete'])) unset($content); |
||
151 | |||
152 | if (!is_array($content)) |
||
153 | { |
||
154 | if (!empty($mailbox)) |
||
155 | { |
||
156 | $content['mailbox'] = $mailbox; |
||
157 | $acl = (array)$this->retrieve_acl($mailbox, $msg); |
||
158 | if ($acl[0] === FALSE) |
||
159 | { |
||
160 | Api\Framework::window_close($msg); |
||
161 | } |
||
162 | $n = 1; |
||
163 | foreach ($acl as $key => $value) |
||
164 | { |
||
165 | $virtuals = array_pop(array_values((array)$value)); |
||
166 | $rights = array_shift(array_values((array)$value)); |
||
167 | |||
168 | foreach ($rights as $right) |
||
169 | { |
||
170 | $content['grid'][$n]['acl_'. $right] = true; |
||
171 | } |
||
172 | $virtualD = array('e','t'); |
||
173 | $content['grid'][$n]['acl_c'] = array_diff($virtuals['c'],array_intersect($rights,$virtuals['c']))? false: true; //c=kx more information rfc4314, Obsolote Rights |
||
174 | $content['grid'][$n]['acl_d'] = array_diff($virtualD,array_intersect($rights,$virtuals['d']))? false: true; //d=et more information rfc4314, Obsolote Rights |
||
175 | |||
176 | sort($rights); |
||
177 | $acl_abbrvs = implode('',$rights); |
||
178 | |||
179 | if (array_key_exists($acl_abbrvs, $this->aclRightsAbbrvs)) |
||
180 | { |
||
181 | $content['grid'][$n]['acl'] = $acl_abbrvs; |
||
182 | } |
||
183 | else |
||
184 | { |
||
185 | $content['grid'][$n]['acl'] = 'custom'; |
||
186 | } |
||
187 | if (($user = $this->imap->getMailBoxAccountId($key))) |
||
188 | { |
||
189 | $content['grid'][$n++]['acc_id'] = $user; |
||
190 | } |
||
191 | else |
||
192 | { |
||
193 | $content['grid'][$n++]['acc_id'] = $key; |
||
194 | } |
||
195 | } |
||
196 | //error_log(__METHOD__."() acl=".array2string($acl).' --> grid='.array2string($content['grid'])); |
||
197 | } |
||
198 | //Set the acl entry in the last row with lrs as default ACL |
||
199 | array_push($content['grid'], array( |
||
200 | 'acc_id'=>'', |
||
201 | 'acl_l' => true, |
||
202 | 'acl_r' => true, |
||
203 | 'acl_s' => true)); |
||
204 | } |
||
205 | else |
||
206 | { |
||
207 | $button = @key($content['button']); |
||
208 | if (!empty ($content['grid']['delete'])) |
||
209 | { |
||
210 | $button = 'delete'; |
||
211 | } |
||
212 | $data = $content; |
||
213 | $data['mailbox'] = self::_extract_mailbox($content['mailbox'], $acc_id); |
||
214 | switch ($button) |
||
215 | { |
||
216 | case 'save': |
||
217 | case 'apply': |
||
218 | if ($content) |
||
219 | { |
||
220 | $validation_err = $this->update_acl($data,$msg); |
||
221 | if ($validation_err) |
||
222 | { |
||
223 | foreach ($validation_err as &$row) |
||
224 | { |
||
225 | $tmpl->set_validation_error('grid['.$row.']'.'[acc_id]', "You must fill this field!"); |
||
226 | } |
||
227 | } |
||
228 | |||
229 | //Add new row at the end |
||
230 | if ($content['grid'][count($content['grid'])]['acc_id']) |
||
231 | array_push($content['grid'], array('acc_id'=>'')); |
||
232 | } |
||
233 | else |
||
234 | { |
||
235 | $msg .= "\n".lang("Error: Could not save ACL").' '.lang("reason!"); |
||
236 | } |
||
237 | //Send message |
||
238 | Framework::message($msg); |
||
239 | if ($button == "apply") break; |
||
240 | Framework::window_close(); |
||
241 | exit; |
||
242 | |||
243 | case 'delete': |
||
244 | $aclRvmCnt = $this->remove_acl($data, $msg); |
||
245 | if (is_array($aclRvmCnt)) |
||
246 | { |
||
247 | $content['grid'] = $aclRvmCnt; |
||
248 | } |
||
249 | else |
||
250 | { |
||
251 | error_log(__METHOD__.__LINE__. "()" . "The remove_acl suppose to return an array back, something is wrong there"); |
||
252 | } |
||
253 | Framework::message($msg); |
||
254 | } |
||
255 | } |
||
256 | $readonlys = $sel_options = array(); |
||
257 | $sel_options['acl'] = $this->aclRightsAbbrvs; |
||
258 | |||
259 | //Make the account owner's fields all readonly as owner has all rights and should not be able to change them |
||
260 | foreach($content['grid'] as $key => $fields) |
||
261 | { |
||
262 | if (self::_extract_acc_id($fields['acc_id']) == $this->imap->acc_imap_username || |
||
263 | $this->imap->getMailBoxUserName(self::_extract_acc_id($fields['acc_id'])) == $this->imap->acc_imap_username) |
||
264 | { |
||
265 | foreach (array_keys($fields) as $index) |
||
266 | { |
||
267 | $readonlys['grid'][$key][$index] = true; |
||
268 | } |
||
269 | $readonlys['grid']['delete['.$key.']'] = true; |
||
270 | $readonlys['grid'][$key]['acl_recursive'] = true; |
||
271 | $preserv ['grid'][$key] = $fields; |
||
272 | $preserv['grid'][$key]['acl_recursive'] = false; |
||
273 | } |
||
274 | if (count($content['grid']) != $key) |
||
275 | { |
||
276 | $preserv ['grid'][$key]['acc_id'] = self::_extract_acc_id($fields['acc_id']); |
||
277 | $preserv['grid'][$key]['acl_recursive'] = false; |
||
278 | $readonlys['grid'][$key]['acc_id'] = true; |
||
279 | } |
||
280 | } |
||
281 | //Make entry row's delete button readonly |
||
282 | $readonlys['grid']['delete['.count($content['grid']).']'] = true; |
||
283 | |||
284 | $preserv['mailbox'] = $content['mailbox']; |
||
285 | $preserv['acc_id'] = $acc_id; |
||
286 | $preserv['account_id'] = $account_id; |
||
287 | $content['grid']['account_type'] = $this->imap->supportsGroupAcl() ? 'both' : 'accounts'; |
||
288 | |||
289 | // set a custom autocomplete method for mailbox taglist |
||
290 | if ($account_id) |
||
291 | { |
||
292 | $tmpl->setElementAttribute('mailbox', 'autocomplete_url', __CLASS__.'::ajax_folders'); |
||
293 | $tmpl->setElementAttribute('mailbox', 'autocomplete_params', array( |
||
294 | 'acc_id' => $acc_id, |
||
295 | 'account_id' => $account_id, |
||
296 | )); |
||
297 | } |
||
298 | |||
299 | $tmpl->exec('mail.mail_acl.edit', $content, $sel_options, $readonlys, $preserv,2); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Autocomplete for folder taglist |
||
304 | * |
||
305 | * @throws Api\Exception\NoPermission\Admin |
||
306 | */ |
||
307 | public static function ajax_folders() |
||
308 | { |
||
309 | if (!empty($_GET['account_id']) && !$GLOBALS['egw_info']['user']['apps']['admin']) |
||
310 | { |
||
311 | throw new Api\Exception\NoPermission\Admin; |
||
312 | } |
||
313 | $account = Mail\Account::read($_GET['acc_id'], $_GET['account_id']); |
||
314 | $imap = $account->imapServer(!empty($_GET['account_id']) ? (int)$_GET['account_id'] : false); |
||
315 | $mailbox = $imap->isAdminConnection ? $imap->getUserMailboxString($imap->isAdminConnection) : 'INBOX'; |
||
316 | |||
317 | $folders = array(); |
||
318 | foreach(self::getSubfolders($mailbox, $imap) as $folder) |
||
319 | { |
||
320 | if (stripos($folder, $_GET['query']) !== false) |
||
321 | { |
||
322 | $folders[] = array( |
||
323 | 'id' => $folder, |
||
324 | 'label' => $folder, |
||
325 | ); |
||
326 | } |
||
327 | } |
||
328 | // switch regular JSON response handling off |
||
329 | Api\Json\Request::isJSONRequest(false); |
||
330 | |||
331 | header('Content-Type: application/json; charset=utf-8'); |
||
332 | echo json_encode($folders); |
||
333 | |||
334 | exit; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Update ACL rights of a folder or including subfolders for an account(s) |
||
339 | * |
||
340 | * @param array $content content including the acl rights |
||
341 | * @param string $msg Message |
||
342 | * |
||
343 | * @return Array | void return array of validation messages or nothing |
||
344 | */ |
||
345 | function update_acl ($content, &$msg) |
||
399 | } |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Retrieve Folder ACL rights |
||
404 | * @param string $mailbox |
||
405 | * @param string &$msg |
||
406 | * |
||
407 | * @return Array | Boolean returns array of acl or false on failure |
||
408 | * @todo rights 'c' and 'd' should be fixed |
||
409 | */ |
||
410 | function retrieve_acl ($mailbox, &$msg) |
||
411 | { |
||
412 | if (($acl = $this->getACL($mailbox))) |
||
413 | { |
||
414 | $msg = lang('ACL rights retrieved successfully'); |
||
415 | return $acl; |
||
416 | } |
||
417 | else |
||
418 | { |
||
419 | $msg = lang('Get ACL rights failed from IMAP server!'); |
||
420 | return false; |
||
421 | } |
||
422 | } |
||
423 | |||
424 | /** |
||
425 | * remove_acl |
||
426 | * This method take content of acl rights, and will delete the one from ACL IMAP, |
||
427 | * for selected folder and/or its subfolders |
||
428 | * |
||
429 | * @param Array $content content array of popup window |
||
430 | * @param string $msg message |
||
431 | * |
||
432 | * @return Array | Boolean An array as new content for grid or false in case of error |
||
433 | */ |
||
434 | function remove_acl($content, &$msg) |
||
435 | { |
||
436 | $row_num = array_keys($content['grid']['delete'],"pressed"); |
||
437 | if ($row_num) $row_num = $row_num[0]; |
||
438 | $recursive = $content['grid'][$row_num]['acl_recursive']; |
||
439 | $identifier = self::_extract_acc_id($content['grid'][$row_num]['acc_id']); |
||
440 | $content['mailbox'] = is_array($content['mailbox'])? $content['mailbox'][0] : $content['mailbox']; |
||
441 | if (is_numeric($identifier) && ($u = $this->imap->getMailBoxUserName($identifier))) |
||
442 | { |
||
443 | $identifier = $u; |
||
444 | } |
||
445 | //error_log(__METHOD__.__LINE__."(".$content['mailbox'].", ".$identifier.", ".$recursive.")"); |
||
446 | if(($res = $this->deleteACL($content['mailbox'], $identifier,$recursive))) |
||
447 | { |
||
448 | unset($content['grid'][$row_num]); |
||
449 | unset($content['grid']['delete']); |
||
450 | if ($recursive) |
||
451 | { |
||
452 | $msg = lang("The %1 's acl, including its subfolders, removed from the %2",$content['mailbox'],$identifier); |
||
453 | } |
||
454 | else |
||
455 | { |
||
456 | $msg = lang("The %1 's acl removed from the %2",$content['mailbox'],$identifier); |
||
457 | } |
||
458 | |||
459 | return array_combine(range(1, count($content['grid'])), array_values($content['grid'])); |
||
460 | } |
||
461 | else |
||
462 | { |
||
463 | $msg = lang("An error happend while trying to remove ACL rights from the account %1!",$identifier); |
||
464 | return false; |
||
465 | } |
||
466 | } |
||
467 | |||
468 | /** |
||
469 | * Delete ACL rights of a folder or including subfolders from an account |
||
470 | * |
||
471 | * @param String $mailbox folder name that needs to be edited |
||
472 | * @param String $identifier The identifier to delete. |
||
473 | * @param Boolean $recursive boolean flag FALSE|TRUE. If it is FALSE, only the folder take in to account, but in case of TRUE |
||
474 | * the mailbox including all its subfolders will be considered. |
||
475 | * |
||
476 | * @return Boolean FALSE in case of any exceptions and TRUE in case of success |
||
477 | */ |
||
478 | function deleteACL ($mailbox, $identifier, $recursive) |
||
479 | { |
||
480 | if ($recursive) |
||
481 | { |
||
482 | $folders = self::getSubfolders($mailbox, $this->imap); |
||
483 | } |
||
484 | else |
||
485 | { |
||
486 | $folders = (array)$mailbox; |
||
487 | } |
||
488 | foreach($folders as $sbFolders) |
||
489 | { |
||
490 | try |
||
491 | { |
||
492 | $this->imap->deleteACL($sbFolders, $identifier); |
||
493 | } |
||
494 | catch (Exception $e) |
||
495 | { |
||
496 | error_log(__METHOD__. "Could not delete ACL rights of folder " . $mailbox . " for account ". $identifier ."." .$e->getMessage()); |
||
497 | return false; |
||
498 | } |
||
499 | } |
||
500 | return true; |
||
501 | } |
||
502 | |||
503 | /** |
||
504 | * Get subfolders of a mailbox |
||
505 | * |
||
506 | * @param string $mailbox structural folder name |
||
507 | * @param Mail\Imap $imap |
||
508 | * @return Array an array including all subfolders of given mailbox| returns an empty array in case of no subfolders |
||
509 | */ |
||
510 | protected static function getSubfolders($mailbox, Mail\Imap $imap) |
||
511 | { |
||
512 | $delimiter = $imap->getDelimiter(); |
||
513 | $nameSpace = $imap->getNameSpace(); |
||
514 | $prefix = $imap->getFolderPrefixFromNamespace($nameSpace, $mailbox); |
||
515 | if (($subFolders = $imap->getMailBoxesRecursive($mailbox, $delimiter, $prefix))) |
||
516 | { |
||
517 | return $subFolders; |
||
518 | } |
||
519 | else |
||
520 | { |
||
521 | return array(); |
||
522 | } |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Set ACL rights of a folder or including subfolders to an account |
||
527 | * @param String $mailbox folder name that needs to be edited |
||
528 | * @param String $identifier The identifier to set. |
||
529 | * @param Array $options Additional options: |
||
530 | * - rights: (string) The rights to alter or set. |
||
531 | * - action: (string, optional) If 'add' or 'remove', adds or removes the |
||
532 | * specified rights. Sets the rights otherwise. |
||
533 | * @param Boolean $recursive boolean flag FALSE|TRUE. If it is FALSE, only the folder take in to account, but in case of TRUE |
||
534 | * the mailbox including all its subfolders will be considered. |
||
535 | * @param String $msg message |
||
536 | * @return Boolean FALSE in case of any exceptions and TRUE in case of success, |
||
537 | * |
||
538 | */ |
||
539 | function setACL($mailbox, $identifier,$options, $recursive, &$msg) |
||
540 | { |
||
541 | if ($recursive) |
||
542 | { |
||
543 | $folders = self::getSubfolders($mailbox, $this->imap); |
||
544 | } |
||
545 | else |
||
546 | { |
||
547 | $folders = (array)$mailbox; |
||
548 | } |
||
549 | foreach($folders as $sbFolders) |
||
550 | { |
||
551 | try |
||
552 | { |
||
553 | $this->imap->setACL($sbFolders,$identifier,$options); |
||
554 | } |
||
555 | catch (Exception $e) |
||
556 | { |
||
557 | $msg = $e->getMessage(); |
||
558 | error_log(__METHOD__. "Could not set ACL rights on folder " . $mailbox . " for account ". $identifier . "." .$e->getMessage()); |
||
559 | return false; |
||
560 | } |
||
561 | } |
||
562 | return true; |
||
563 | } |
||
564 | |||
565 | /** |
||
566 | * Get ACL rights of a folder from an account |
||
567 | * |
||
568 | * @param String $mailbox folder name that needs to be read |
||
569 | * @return Array|Boolean FALSE in case of any exceptions and returns Array in case of success, |
||
570 | */ |
||
571 | function getACL ($mailbox) |
||
572 | { |
||
573 | try |
||
574 | { |
||
575 | return $this->imap->getACL($mailbox); |
||
576 | } catch (Exception $e) { |
||
577 | error_log(__METHOD__. "Could not get ACL rights from folder " . $mailbox . "." .$e->getMessage()); |
||
578 | return false; |
||
579 | } |
||
580 | } |
||
581 | |||
582 | /** |
||
583 | * Method to get acc_id id value whether if is a flat value or an array |
||
584 | * |
||
585 | * @param type $acc_id acc_id value comming from client-side |
||
586 | * |
||
587 | * @return string returns acc_id in flat format |
||
588 | */ |
||
589 | private static function _extract_acc_id ($acc_id) |
||
590 | { |
||
591 | return is_array($acc_id)?$acc_id[0]:$acc_id; |
||
592 | } |
||
593 | |||
594 | /** |
||
595 | * @param string | array $mailbox |
||
596 | * @param string $acc_id |
||
597 | * |
||
598 | * @return string | NULL return sanitate mailbox of acc id and delimiter and return it as string |
||
599 | */ |
||
600 | private static function _extract_mailbox ($mailbox, $acc_id) |
||
604 | } |
||
605 | } |
||
606 |
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: