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 InheritedPermissions 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 InheritedPermissions, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class InheritedPermissions implements PermissionChecker |
||
20 | { |
||
21 | use Injectable; |
||
22 | |||
23 | /** |
||
24 | * Delete permission |
||
25 | */ |
||
26 | const DELETE = 'delete'; |
||
27 | |||
28 | /** |
||
29 | * View permission |
||
30 | */ |
||
31 | const VIEW = 'view'; |
||
32 | |||
33 | /** |
||
34 | * Edit permission |
||
35 | */ |
||
36 | const EDIT = 'edit'; |
||
37 | |||
38 | /** |
||
39 | * Anyone canView permission |
||
40 | */ |
||
41 | const ANYONE = 'Anyone'; |
||
42 | |||
43 | /** |
||
44 | * Restrict to logged in users |
||
45 | */ |
||
46 | const LOGGED_IN_USERS = 'LoggedInUsers'; |
||
47 | |||
48 | /** |
||
49 | * Restrict to specific groups |
||
50 | */ |
||
51 | const ONLY_THESE_USERS = 'OnlyTheseUsers'; |
||
52 | |||
53 | /** |
||
54 | * Inherit from parent |
||
55 | */ |
||
56 | const INHERIT = 'Inherit'; |
||
57 | |||
58 | /** |
||
59 | * Class name |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | protected $baseClass = null; |
||
64 | |||
65 | /** |
||
66 | * Object for evaluating top level permissions designed as "Inherit" |
||
67 | * |
||
68 | * @var DefaultPermissionChecker |
||
69 | */ |
||
70 | protected $defaultPermissions = null; |
||
71 | |||
72 | /** |
||
73 | * Global permissions required to edit. |
||
74 | * If empty no global permissions are required |
||
75 | * |
||
76 | * @var array |
||
77 | */ |
||
78 | protected $globalEditPermissions = []; |
||
79 | |||
80 | /** |
||
81 | * Cache of permissions |
||
82 | * |
||
83 | * @var array |
||
84 | */ |
||
85 | protected $cachePermissions = []; |
||
86 | |||
87 | /** |
||
88 | * Construct new permissions object |
||
89 | * |
||
90 | * @param string $baseClass Base class |
||
91 | */ |
||
92 | public function __construct($baseClass) |
||
100 | |||
101 | /** |
||
102 | * @param DefaultPermissionChecker $callback |
||
103 | * @return $this |
||
104 | */ |
||
105 | public function setDefaultPermissions(DefaultPermissionChecker $callback) |
||
110 | |||
111 | /** |
||
112 | * Global permissions required to edit |
||
113 | * |
||
114 | * @param array $permissions |
||
115 | * @return $this |
||
116 | */ |
||
117 | public function setGlobalEditPermissions($permissions) |
||
122 | |||
123 | /** |
||
124 | * @return array |
||
125 | */ |
||
126 | public function getGlobalEditPermissions() |
||
130 | |||
131 | /** |
||
132 | * Get root permissions handler, or null if no handler |
||
133 | * |
||
134 | * @return DefaultPermissionChecker|null |
||
135 | */ |
||
136 | public function getDefaultPermissions() |
||
140 | |||
141 | /** |
||
142 | * Get base class |
||
143 | * |
||
144 | * @return string |
||
145 | */ |
||
146 | public function getBaseClass() |
||
150 | |||
151 | /** |
||
152 | * Force pre-calculation of a list of permissions for optimisation |
||
153 | * |
||
154 | * @param string $permission |
||
155 | * @param array $ids |
||
156 | */ |
||
157 | public function prePopulatePermissionCache($permission = 'edit', $ids = []) |
||
173 | |||
174 | /** |
||
175 | * This method is NOT a full replacement for the individual can*() methods, e.g. {@link canEdit()}. Rather than |
||
176 | * checking (potentially slow) PHP logic, it relies on the database group associations, e.g. the "CanEditType" field |
||
177 | * plus the "SiteTree_EditorGroups" many-many table. By batch checking multiple records, we can combine the queries |
||
178 | * efficiently. |
||
179 | * |
||
180 | * Caches based on $typeField data. To invalidate the cache, use {@link SiteTree::reset()} or set the $useCached |
||
181 | * property to FALSE. |
||
182 | * |
||
183 | * @param string $type Either edit, view, or create |
||
184 | * @param array $ids Array of IDs |
||
185 | * @param Member $member Member |
||
186 | * @param array $globalPermission If the member doesn't have this permission code, don't bother iterating deeper |
||
187 | * @param bool $useCached Enables use of cache. Cache will be populated even if this is false. |
||
188 | * @return array A map of permissions, keys are ID numbers, and values are boolean permission checks |
||
189 | * ID keys to boolean values |
||
190 | */ |
||
191 | protected function batchPermissionCheck( |
||
282 | |||
283 | /** |
||
284 | * @param string $type |
||
285 | * @param array $globalPermission List of global permissions |
||
286 | * @param DataList $stageRecords List of records to check for this stage |
||
287 | * @param string $groupIDsSQLList Group IDs this member belongs to |
||
288 | * @param Member $member |
||
289 | * @return array |
||
290 | */ |
||
291 | protected function batchPermissionCheckForStage( |
||
369 | |||
370 | public function canEditMultiple($ids, Member $member = null, $useCached = true) |
||
380 | |||
381 | public function canViewMultiple($ids, Member $member = null, $useCached = true) |
||
385 | |||
386 | public function canDeleteMultiple($ids, Member $member = null, $useCached = true) |
||
453 | |||
454 | View Code Duplication | public function canDelete($id, Member $member = null) |
|
470 | |||
471 | View Code Duplication | public function canEdit($id, Member $member = null) |
|
487 | |||
488 | View Code Duplication | public function canView($id, Member $member = null) |
|
504 | |||
505 | /** |
||
506 | * Get field to check for permission type for the given check. |
||
507 | * Defaults to those provided by {@see InheritedPermissionsExtension) |
||
508 | * |
||
509 | * @param string $type |
||
510 | * @return string |
||
511 | */ |
||
512 | protected function getPermissionField($type) |
||
525 | |||
526 | /** |
||
527 | * Get join table for type |
||
528 | * Defaults to those provided by {@see InheritedPermissionsExtension) |
||
529 | * |
||
530 | * @param string $type |
||
531 | * @return string |
||
532 | */ |
||
533 | protected function getJoinTable($type) |
||
546 | |||
547 | /** |
||
548 | * Determine default permission for a givion check |
||
549 | * |
||
550 | * @param string $type Method to check |
||
551 | * @param Member $member |
||
552 | * @return bool |
||
553 | */ |
||
554 | protected function checkDefaultPermissions($type, Member $member = null) |
||
571 | |||
572 | /** |
||
573 | * Check if this model has versioning |
||
574 | * |
||
575 | * @return bool |
||
576 | */ |
||
577 | protected function isVersioned() |
||
585 | |||
586 | public function clearCache() |
||
591 | |||
592 | /** |
||
593 | * Get table to use for editor groups relation |
||
594 | * |
||
595 | * @return string |
||
596 | */ |
||
597 | protected function getEditorGroupsTable() |
||
602 | |||
603 | /** |
||
604 | * Get table to use for viewer groups relation |
||
605 | * |
||
606 | * @return string |
||
607 | */ |
||
608 | protected function getViewerGroupsTable() |
||
613 | } |
||
614 |