Complex classes like admin_plugin_usermanager 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 admin_plugin_usermanager, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
22 | class admin_plugin_usermanager extends DokuWiki_Admin_Plugin { |
||
23 | |||
24 | protected $_auth = null; // auth object |
||
25 | protected $_user_total = 0; // number of registered users |
||
26 | protected $_filter = array(); // user selection filter(s) |
||
27 | protected $_start = 0; // index of first user to be displayed |
||
28 | protected $_last = 0; // index of the last user to be displayed |
||
29 | protected $_pagesize = 20; // number of users to list on one page |
||
30 | protected $_edit_user = ''; // set to user selected for editing |
||
31 | protected $_edit_userdata = array(); |
||
32 | protected $_disabled = ''; // if disabled set to explanatory string |
||
33 | protected $_import_failures = array(); |
||
34 | protected $_lastdisabled = false; // set to true if last user is unknown and last button is hence buggy |
||
35 | |||
36 | /** |
||
37 | * Constructor |
||
38 | */ |
||
39 | public function __construct(){ |
||
40 | /** @var DokuWiki_Auth_Plugin $auth */ |
||
41 | global $auth; |
||
42 | |||
43 | $this->setupLocale(); |
||
44 | |||
45 | if (!isset($auth)) { |
||
46 | $this->_disabled = $this->lang['noauth']; |
||
|
|||
47 | } else if (!$auth->canDo('getUsers')) { |
||
48 | $this->_disabled = $this->lang['nosupport']; |
||
49 | } else { |
||
50 | |||
51 | // we're good to go |
||
52 | $this->_auth = & $auth; |
||
53 | |||
54 | } |
||
55 | |||
56 | // attempt to retrieve any import failures from the session |
||
57 | if (!empty($_SESSION['import_failures'])){ |
||
58 | $this->_import_failures = $_SESSION['import_failures']; |
||
59 | } |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * Return prompt for admin menu |
||
64 | * |
||
65 | * @param string $language |
||
66 | * @return string |
||
67 | */ |
||
68 | public function getMenuText($language) { |
||
69 | |||
70 | if (!is_null($this->_auth)) |
||
71 | return parent::getMenuText($language); |
||
72 | |||
73 | return $this->getLang('menu').' '.$this->_disabled; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * return sort order for position in admin menu |
||
78 | * |
||
79 | * @return int |
||
80 | */ |
||
81 | public function getMenuSort() { |
||
82 | return 2; |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * @return int current start value for pageination |
||
87 | */ |
||
88 | public function getStart() { |
||
89 | return $this->_start; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @return int number of users per page |
||
94 | */ |
||
95 | public function getPagesize() { |
||
96 | return $this->_pagesize; |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * @param boolean $lastdisabled |
||
101 | */ |
||
102 | public function setLastdisabled($lastdisabled) { |
||
103 | $this->_lastdisabled = $lastdisabled; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Handle user request |
||
108 | * |
||
109 | * @return bool |
||
110 | */ |
||
111 | public function handle() { |
||
112 | global $INPUT; |
||
113 | if (is_null($this->_auth)) return false; |
||
114 | |||
115 | // extract the command and any specific parameters |
||
116 | // submit button name is of the form - fn[cmd][param(s)] |
||
117 | $fn = $INPUT->param('fn'); |
||
118 | |||
119 | if (is_array($fn)) { |
||
120 | $cmd = key($fn); |
||
121 | $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; |
||
122 | } else { |
||
123 | $cmd = $fn; |
||
124 | $param = null; |
||
125 | } |
||
126 | |||
127 | if ($cmd != "search") { |
||
128 | $this->_start = $INPUT->int('start', 0); |
||
129 | $this->_filter = $this->_retrieveFilter(); |
||
130 | } |
||
131 | |||
132 | switch($cmd){ |
||
133 | case "add" : $this->_addUser(); break; |
||
134 | case "delete" : $this->_deleteUser(); break; |
||
135 | case "modify" : $this->_modifyUser(); break; |
||
136 | case "edit" : $this->_editUser($param); break; |
||
137 | case "search" : $this->_setFilter($param); |
||
138 | $this->_start = 0; |
||
139 | break; |
||
140 | case "export" : $this->_export(); break; |
||
141 | case "import" : $this->_import(); break; |
||
142 | case "importfails" : $this->_downloadImportFailures(); break; |
||
143 | } |
||
144 | |||
145 | $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1; |
||
146 | |||
147 | // page handling |
||
148 | switch($cmd){ |
||
149 | case 'start' : $this->_start = 0; break; |
||
150 | case 'prev' : $this->_start -= $this->_pagesize; break; |
||
151 | case 'next' : $this->_start += $this->_pagesize; break; |
||
152 | case 'last' : $this->_start = $this->_user_total; break; |
||
153 | } |
||
154 | $this->_validatePagination(); |
||
155 | return true; |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Output appropriate html |
||
160 | * |
||
161 | * @return bool |
||
162 | */ |
||
163 | public function html() { |
||
164 | global $ID; |
||
165 | |||
166 | if(is_null($this->_auth)) { |
||
167 | print $this->lang['badauth']; |
||
168 | return false; |
||
169 | } |
||
170 | |||
171 | $user_list = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter); |
||
172 | |||
173 | $page_buttons = $this->_pagination(); |
||
174 | $delete_disable = $this->_auth->canDo('delUser') ? '' : 'disabled="disabled"'; |
||
175 | |||
176 | $editable = $this->_auth->canDo('UserMod'); |
||
177 | $export_label = empty($this->_filter) ? $this->lang['export_all'] : $this->lang['export_filtered']; |
||
178 | |||
179 | print $this->locale_xhtml('intro'); |
||
180 | print $this->locale_xhtml('list'); |
||
181 | |||
182 | ptln("<div id=\"user__manager\">"); |
||
183 | ptln("<div class=\"level2\">"); |
||
184 | |||
185 | if ($this->_user_total > 0) { |
||
186 | ptln("<p>".sprintf($this->lang['summary'],$this->_start+1,$this->_last,$this->_user_total,$this->_auth->getUserCount())."</p>"); |
||
187 | } else { |
||
188 | if($this->_user_total < 0) { |
||
189 | $allUserTotal = 0; |
||
190 | } else { |
||
191 | $allUserTotal = $this->_auth->getUserCount(); |
||
192 | } |
||
193 | ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>"); |
||
194 | } |
||
195 | ptln("<form action=\"".wl($ID)."\" method=\"post\">"); |
||
196 | formSecurityToken(); |
||
197 | ptln(" <div class=\"table\">"); |
||
198 | ptln(" <table class=\"inline\">"); |
||
199 | ptln(" <thead>"); |
||
200 | ptln(" <tr>"); |
||
201 | ptln(" <th> </th><th>".$this->lang["user_id"]."</th><th>".$this->lang["user_name"]."</th><th>".$this->lang["user_mail"]."</th><th>".$this->lang["user_groups"]."</th>"); |
||
202 | ptln(" </tr>"); |
||
203 | |||
204 | ptln(" <tr>"); |
||
205 | ptln(" <td class=\"rightalign\"><input type=\"image\" src=\"".DOKU_PLUGIN_IMAGES."search.png\" name=\"fn[search][new]\" title=\"".$this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>"); |
||
206 | ptln(" <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"".$this->_htmlFilter('user')."\" /></td>"); |
||
207 | ptln(" <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"".$this->_htmlFilter('name')."\" /></td>"); |
||
208 | ptln(" <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"".$this->_htmlFilter('mail')."\" /></td>"); |
||
209 | ptln(" <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"".$this->_htmlFilter('grps')."\" /></td>"); |
||
210 | ptln(" </tr>"); |
||
211 | ptln(" </thead>"); |
||
212 | |||
213 | if ($this->_user_total) { |
||
214 | ptln(" <tbody>"); |
||
215 | foreach ($user_list as $user => $userinfo) { |
||
216 | extract($userinfo); |
||
217 | /** |
||
218 | * @var string $name |
||
219 | * @var string $pass |
||
220 | * @var string $mail |
||
221 | * @var array $grps |
||
222 | */ |
||
223 | $groups = join(', ',$grps); |
||
224 | ptln(" <tr class=\"user_info\">"); |
||
225 | ptln(" <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user)."]\" ".$delete_disable." /></td>"); |
||
226 | if ($editable) { |
||
227 | ptln(" <td><a href=\"".wl($ID,array('fn[edit]['.$user.']' => 1, |
||
228 | 'do' => 'admin', |
||
229 | 'page' => 'usermanager', |
||
230 | 'sectok' => getSecurityToken())). |
||
231 | "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."</a></td>"); |
||
232 | } else { |
||
233 | ptln(" <td>".hsc($user)."</td>"); |
||
234 | } |
||
235 | ptln(" <td>".hsc($name)."</td><td>".hsc($mail)."</td><td>".hsc($groups)."</td>"); |
||
236 | ptln(" </tr>"); |
||
237 | } |
||
238 | ptln(" </tbody>"); |
||
239 | } |
||
240 | |||
241 | ptln(" <tbody>"); |
||
242 | ptln(" <tr><td colspan=\"5\" class=\"centeralign\">"); |
||
243 | ptln(" <span class=\"medialeft\">"); |
||
244 | ptln(" <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">".$this->lang['delete_selected']."</button>"); |
||
245 | ptln(" </span>"); |
||
246 | ptln(" <span class=\"mediaright\">"); |
||
247 | ptln(" <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">".$this->lang['start']."</button>"); |
||
248 | ptln(" <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">".$this->lang['prev']."</button>"); |
||
249 | ptln(" <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">".$this->lang['next']."</button>"); |
||
250 | ptln(" <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">".$this->lang['last']."</button>"); |
||
251 | ptln(" </span>"); |
||
252 | if (!empty($this->_filter)) { |
||
253 | ptln(" <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>"); |
||
254 | } |
||
255 | ptln(" <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>"); |
||
256 | ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />"); |
||
257 | ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />"); |
||
258 | |||
259 | $this->_htmlFilterSettings(2); |
||
260 | |||
261 | ptln(" </td></tr>"); |
||
262 | ptln(" </tbody>"); |
||
263 | ptln(" </table>"); |
||
264 | ptln(" </div>"); |
||
265 | |||
266 | ptln("</form>"); |
||
267 | ptln("</div>"); |
||
268 | |||
269 | $style = $this->_edit_user ? " class=\"edit_user\"" : ""; |
||
270 | |||
271 | if ($this->_auth->canDo('addUser')) { |
||
272 | ptln("<div".$style.">"); |
||
273 | print $this->locale_xhtml('add'); |
||
274 | ptln(" <div class=\"level2\">"); |
||
275 | |||
276 | $this->_htmlUserForm('add',null,array(),4); |
||
277 | |||
278 | ptln(" </div>"); |
||
279 | ptln("</div>"); |
||
280 | } |
||
281 | |||
282 | if($this->_edit_user && $this->_auth->canDo('UserMod')){ |
||
283 | ptln("<div".$style." id=\"scroll__here\">"); |
||
284 | print $this->locale_xhtml('edit'); |
||
285 | ptln(" <div class=\"level2\">"); |
||
286 | |||
287 | $this->_htmlUserForm('modify',$this->_edit_user,$this->_edit_userdata,4); |
||
288 | |||
289 | ptln(" </div>"); |
||
290 | ptln("</div>"); |
||
291 | } |
||
292 | |||
293 | if ($this->_auth->canDo('addUser')) { |
||
294 | $this->_htmlImportForm(); |
||
295 | } |
||
296 | ptln("</div>"); |
||
297 | return true; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Display form to add or modify a user |
||
302 | * |
||
303 | * @param string $cmd 'add' or 'modify' |
||
304 | * @param string $user id of user |
||
305 | * @param array $userdata array with name, mail, pass and grps |
||
306 | * @param int $indent |
||
307 | */ |
||
308 | protected function _htmlUserForm($cmd,$user='',$userdata=array(),$indent=0) { |
||
379 | |||
380 | /** |
||
381 | * Prints a inputfield |
||
382 | * |
||
383 | * @param string $id |
||
384 | * @param string $name |
||
385 | * @param string $label |
||
386 | * @param string $value |
||
387 | * @param bool $cando whether auth backend is capable to do this action |
||
388 | * @param bool $required is this field required? |
||
389 | * @param int $indent |
||
390 | */ |
||
391 | protected function _htmlInputField($id, $name, $label, $value, $cando, $required, $indent=0) { |
||
421 | |||
422 | /** |
||
423 | * Returns htmlescaped filter value |
||
424 | * |
||
425 | * @param string $key name of search field |
||
426 | * @return string html escaped value |
||
427 | */ |
||
428 | protected function _htmlFilter($key) { |
||
429 | if (empty($this->_filter)) return ''; |
||
432 | |||
433 | /** |
||
434 | * Print hidden inputs with the current filter values |
||
435 | * |
||
436 | * @param int $indent |
||
437 | */ |
||
438 | protected function _htmlFilterSettings($indent=0) { |
||
446 | |||
447 | /** |
||
448 | * Print import form and summary of previous import |
||
449 | * |
||
450 | * @param int $indent |
||
451 | */ |
||
452 | protected function _htmlImportForm($indent=0) { |
||
504 | |||
505 | /** |
||
506 | * Add an user to auth backend |
||
507 | * |
||
508 | * @return bool whether succesful |
||
509 | */ |
||
510 | protected function _addUser(){ |
||
584 | |||
585 | /** |
||
586 | * Delete user from auth backend |
||
587 | * |
||
588 | * @return bool whether succesful |
||
589 | */ |
||
590 | protected function _deleteUser(){ |
||
620 | |||
621 | /** |
||
622 | * Edit user (a user has been selected for editing) |
||
623 | * |
||
624 | * @param string $param id of the user |
||
625 | * @return bool whether succesful |
||
626 | */ |
||
627 | protected function _editUser($param) { |
||
644 | |||
645 | /** |
||
646 | * Modify user in the auth backend (modified user data has been recieved) |
||
647 | * |
||
648 | * @return bool whether succesful |
||
649 | */ |
||
650 | protected function _modifyUser(){ |
||
726 | |||
727 | /** |
||
728 | * Send password change notification email |
||
729 | * |
||
730 | * @param string $user id of user |
||
731 | * @param string $password plain text |
||
732 | * @param bool $status_alert whether status alert should be shown |
||
733 | * @return bool whether succesful |
||
734 | */ |
||
735 | protected function _notifyUser($user, $password, $status_alert=true) { |
||
749 | |||
750 | /** |
||
751 | * Verify password meets minimum requirements |
||
752 | * :TODO: extend to support password strength |
||
753 | * |
||
754 | * @param string $password candidate string for new password |
||
755 | * @param string $confirm repeated password for confirmation |
||
756 | * @return bool true if meets requirements, false otherwise |
||
757 | */ |
||
758 | protected function _verifyPassword($password, $confirm) { |
||
775 | |||
776 | /** |
||
777 | * Retrieve & clean user data from the form |
||
778 | * |
||
779 | * @param bool $clean whether the cleanUser method of the authentication backend is applied |
||
780 | * @return array (user, password, full name, email, array(groups)) |
||
781 | */ |
||
782 | protected function _retrieveUser($clean=true) { |
||
803 | |||
804 | /** |
||
805 | * Set the filter with the current search terms or clear the filter |
||
806 | * |
||
807 | * @param string $op 'new' or 'clear' |
||
808 | */ |
||
809 | protected function _setFilter($op) { |
||
822 | |||
823 | /** |
||
824 | * Get the current search terms |
||
825 | * |
||
826 | * @return array |
||
827 | */ |
||
828 | protected function _retrieveFilter() { |
||
843 | |||
844 | /** |
||
845 | * Validate and improve the pagination values |
||
846 | */ |
||
847 | protected function _validatePagination() { |
||
856 | |||
857 | /** |
||
858 | * Return an array of strings to enable/disable pagination buttons |
||
859 | * |
||
860 | * @return array with enable/disable attributes |
||
861 | */ |
||
862 | protected function _pagination() { |
||
882 | |||
883 | /** |
||
884 | * Export a list of users in csv format using the current filter criteria |
||
885 | */ |
||
886 | protected function _export() { |
||
916 | |||
917 | /** |
||
918 | * Import a file of users in csv format |
||
919 | * |
||
920 | * csv file should have 4 columns, user_id, full name, email, groups (comma separated) |
||
921 | * |
||
922 | * @return bool whether successful |
||
923 | */ |
||
924 | protected function _import() { |
||
987 | |||
988 | /** |
||
989 | * Returns cleaned user data |
||
990 | * |
||
991 | * @param array $candidate raw values of line from input file |
||
992 | * @param string $error |
||
993 | * @return array|false cleaned data or false |
||
994 | */ |
||
995 | protected function _cleanImportUser($candidate, & $error){ |
||
1033 | |||
1034 | /** |
||
1035 | * Adds imported user to auth backend |
||
1036 | * |
||
1037 | * Required a check of canDo('addUser') before |
||
1038 | * |
||
1039 | * @param array $user data of user |
||
1040 | * @param string &$error reference catched error message |
||
1041 | * @return bool whether successful |
||
1042 | */ |
||
1043 | protected function _addImportUser($user, & $error){ |
||
1051 | |||
1052 | /** |
||
1053 | * Downloads failures as csv file |
||
1054 | */ |
||
1055 | protected function _downloadImportFailures(){ |
||
1073 | |||
1074 | /** |
||
1075 | * wrapper for is_uploaded_file to facilitate overriding by test suite |
||
1076 | * |
||
1077 | * @param string $file filename |
||
1078 | * @return bool |
||
1079 | */ |
||
1080 | protected function _isUploadedFile($file) { |
||
1083 | } |
||
1084 |
This check looks for access to properties that are not accessible from the current context.
If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.