Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Api 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 Api, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class Api { |
||
10 | |||
11 | const DEFAULT_ROLE = 'default'; |
||
12 | const ADMIN_ROLE = 'admin'; |
||
13 | const VISITOR_ROLE = 'visitor'; |
||
14 | const NO_ROLE = '_no_role_'; |
||
15 | const DENY = 'deny'; |
||
16 | const ALLOW = 'allow'; |
||
17 | const REPLACE = 'replace'; |
||
18 | const EXTEND = 'extend'; |
||
19 | const REDIRECT = 'redirect'; |
||
20 | const FORWARD = 'forward'; |
||
21 | |||
22 | /** |
||
23 | * @var DbInterface |
||
24 | */ |
||
25 | private $db; |
||
26 | |||
27 | /** |
||
28 | * Permissions cache |
||
29 | * @var array |
||
30 | */ |
||
31 | private $cache; |
||
32 | |||
33 | /** |
||
34 | * Roles cache |
||
35 | * @var ElggRole[] |
||
36 | */ |
||
37 | private $roles; |
||
38 | |||
39 | /** |
||
40 | * Constructor |
||
41 | */ |
||
42 | 41 | public function __construct(DbInterface $db) { |
|
46 | |||
47 | /** |
||
48 | * Obtains the role of a given user |
||
49 | * |
||
50 | * @param ElggUser $user User entity |
||
51 | * @return ElggRole The role the user belongs to |
||
52 | */ |
||
53 | 1 | public function getRole(ElggUser $user) { |
|
57 | |||
58 | /** |
||
59 | * Checks if the user has a specific role |
||
60 | * |
||
61 | * @param ElggUser $user User entity |
||
62 | * @return bool True if the user belongs to the passed role, false otherwise |
||
63 | */ |
||
64 | public function hasRole(ElggUser $user, $role_name = self::DEFAULT_ROLE) { |
||
67 | |||
68 | /** |
||
69 | * Assigns a role to a particular user |
||
70 | * |
||
71 | * @param ElggUser $user The user the role needs to be assigned to |
||
72 | * @param ElggRole $role The role to be assigned |
||
73 | * @return bool|void True if the role change was successful, false if could not update user role, and null if there was no change in user role |
||
74 | */ |
||
75 | 1 | public function setRole(ElggUser $user, ElggRole $role) { |
|
94 | |||
95 | /** |
||
96 | * Clear user roles |
||
97 | * |
||
98 | * @param ElggUser $user User entity |
||
99 | * @return bool |
||
100 | */ |
||
101 | 1 | public function unsetRole(ElggUser $user) { |
|
104 | |||
105 | /** |
||
106 | * Gets all role objects |
||
107 | * @return ElggRole[]|false An array of ElggRole objects defined in the system, or false if none found |
||
108 | */ |
||
109 | 27 | public function getAll() { |
|
120 | |||
121 | /** |
||
122 | * Gets all non-default role objects |
||
123 | * |
||
124 | * This is used by the role selector view. Default roles (VISITOR_ROLE, ADMIN_ROLE, DEFAULT_ROLE) need to be omitted from |
||
125 | * the list of selectable roles - as default roles are automatically assigned to users based on their Elgg membership type |
||
126 | * |
||
127 | * @return ElggRole[]|false An array of non-default ElggRole objects defined in the system, or false if none found |
||
128 | */ |
||
129 | 1 | public function getSelectable() { |
|
135 | |||
136 | /** |
||
137 | * Obtains a list of permissions associated with a particular role object |
||
138 | * |
||
139 | * @param ElggRole $role The role to check for permissions |
||
140 | * @param string $permission_type The section from the configuration array ('actions', 'menus', 'views', etc.) |
||
141 | * @return array The permission rules for the given role and permission type |
||
142 | */ |
||
143 | 24 | public function getPermissions(ElggRole $role, $permission_type = null) { |
|
154 | |||
155 | /** |
||
156 | * Caches permissions associated with a role object. Also resolves all role extensions. |
||
157 | * |
||
158 | * @param ElggRole $role The role to cache permissions for |
||
159 | * @return void |
||
160 | */ |
||
161 | 24 | public function cachePermissions(ElggRole $role) { |
|
197 | |||
198 | /** |
||
199 | * Gets a role object based on it's name |
||
200 | * |
||
201 | * @param string $role_name The name of the role |
||
202 | * @return ElggRole|false An ElggRole object if it could be found based on the name, false otherwise |
||
203 | */ |
||
204 | 27 | public function getRoleByName($role_name = '') { |
|
208 | |||
209 | /** |
||
210 | * Resolves the default role for specified or currently logged in user |
||
211 | * |
||
212 | * @param string $role_name The name of the user's role |
||
213 | * @param ElggUser $user User whose default role needs to be resolved |
||
214 | * @return string |
||
215 | */ |
||
216 | 2 | public function filterName($role_name, ElggUser $user = null) { |
|
227 | |||
228 | /** |
||
229 | * Processes the configuration files and generates the appropriate ElggRole objects. |
||
230 | * |
||
231 | * If, for any role definition, there is an already existing role with the same name, |
||
232 | * the role permissions will be updated for the given role object. |
||
233 | * If there is no previously existing, corresponding role object, it will be created now. |
||
234 | * |
||
235 | * @param array $roles_array The roles configuration array |
||
236 | * @return void |
||
237 | */ |
||
238 | public function createFromConfig($roles_array) { |
||
287 | |||
288 | /** |
||
289 | * Checks if the configuration array has been updated and updates role objects accordingly if needed |
||
290 | * @return void |
||
291 | */ |
||
292 | public function checkUpdate() { |
||
303 | |||
304 | /** |
||
305 | * Substitutes dynamic parts of a menu's target URL |
||
306 | * |
||
307 | * @param array $vars An associative array holding the menu permissions |
||
308 | * @return The substituted menu permission array |
||
309 | */ |
||
310 | 2 | public function prepareMenuVars($vars) { |
|
319 | |||
320 | /** |
||
321 | * Replaces certain parts of path and URL type definitions with dynamic values |
||
322 | * |
||
323 | * @param string $str The string to operate on |
||
324 | * @return string The updated, substituted string |
||
325 | */ |
||
326 | 10 | public function replaceDynamicPaths($str) { |
|
356 | |||
357 | /** |
||
358 | * Checks if a path or URL type rule matches a given path. Also processes regular expressions |
||
359 | * |
||
360 | * @param string $rule The permission rule to check |
||
361 | * @param string $path The path to match against |
||
362 | * @return bool True if the rule matches the path, false otherwise |
||
363 | */ |
||
364 | 15 | public function matchPath($rule, $path) { |
|
377 | |||
378 | /** |
||
379 | * Checks if a permission rule should be executed for the current context |
||
380 | * |
||
381 | * @param string $permission_details The permission rule configuration |
||
382 | * @param boolean $strict If strict context matching should be used. |
||
383 | * If true, only the last context will be checked for the rule matching. |
||
384 | * If false, any context value in the context stack will be considered. |
||
385 | * @return bool True if the rule should be executed, false otherwise |
||
386 | */ |
||
387 | 6 | public function checkContext($permission_details, $strict = false) { |
|
401 | |||
402 | /** |
||
403 | * Gets all reserved role names |
||
404 | * @return array The list of reserved role names |
||
405 | */ |
||
406 | 4 | public function getReservedRoleNames() { |
|
409 | |||
410 | /** |
||
411 | * |
||
412 | * Checks if a role name is reserved in the system |
||
413 | * |
||
414 | * @param string $role_name The name of the role to check |
||
415 | * @return boolean True if the passed $role_name is a reserved role name |
||
416 | */ |
||
417 | 3 | public function isReservedRoleName($role_name) { |
|
420 | |||
421 | /** |
||
422 | * Setup views for a given role |
||
423 | * |
||
424 | * @param ElggRole $role Role |
||
425 | * @return void |
||
426 | */ |
||
427 | 4 | public function setupViews(\ElggRole $role) { |
|
458 | |||
459 | /** |
||
460 | * Supresses view output |
||
461 | * @return string |
||
462 | */ |
||
463 | 1 | public function supressView() { |
|
466 | |||
467 | /** |
||
468 | * Setup hooks for a given role |
||
469 | * |
||
470 | * @param ElggRole $role Role object |
||
471 | * @return void |
||
472 | */ |
||
473 | 4 | public function setupHooks(\ElggRole $role) { |
|
520 | |||
521 | /** |
||
522 | * Setup events for a given role |
||
523 | * |
||
524 | * @param ElggRole $role Role object |
||
525 | * @return void |
||
526 | */ |
||
527 | 4 | function setupEvents(\ElggRole $role) { |
|
575 | |||
576 | /** |
||
577 | * Check action access permissions for a given role |
||
578 | * |
||
579 | * @param ElggRole $role Role object |
||
580 | * @param string $action Registered action name |
||
581 | * @return boolean|void |
||
582 | */ |
||
583 | 2 | function actionGatekeeper(\ElggRole $role, $action = '') { |
|
595 | |||
596 | /** |
||
597 | * Check page access permissions for a given role |
||
598 | * |
||
599 | * @param ElggRole $role Role object |
||
600 | * @param string $path URL path |
||
601 | * @return array |
||
602 | */ |
||
603 | 3 | function pageGatekeeper(\ElggRole $role, $path = '') { |
|
632 | |||
633 | /** |
||
634 | * Setup menu |
||
635 | * |
||
636 | * @param ElggRole $role Role object |
||
637 | * @param string $menu_name Menu name |
||
638 | * @param ElggMenuItem[] $menu Menu items |
||
639 | * @return ElggMenuItem[] |
||
640 | */ |
||
641 | 4 | public function setupMenu(\ElggRole $role, $menu_name = '', $menu = array()) { |
|
714 | |||
715 | /** |
||
716 | * Remove items that link to denied pages and actions |
||
717 | * |
||
718 | * @param ElggRole $role Role object |
||
719 | * @param ElggMenuItem[] $menu Menu |
||
720 | * @return ElggMenuItem[] |
||
721 | */ |
||
722 | 1 | public function cleanMenu(\ElggRole $role, $menu = array()) { |
|
765 | |||
766 | } |
||
767 |