Complex classes like PhpManager 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 PhpManager, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class PhpManager extends BaseManager |
||
38 | { |
||
39 | /** |
||
40 | * @var string the path of the PHP script that contains the authorization items. |
||
41 | * This can be either a file path or a [path alias](guide:concept-aliases) to the file. |
||
42 | * Make sure this file is writable by the Web server process if the authorization needs to be changed online. |
||
43 | * @see loadFromFile() |
||
44 | * @see saveToFile() |
||
45 | */ |
||
46 | public $itemFile = '@app/rbac/items.php'; |
||
47 | /** |
||
48 | * @var string the path of the PHP script that contains the authorization assignments. |
||
49 | * This can be either a file path or a [path alias](guide:concept-aliases) to the file. |
||
50 | * Make sure this file is writable by the Web server process if the authorization needs to be changed online. |
||
51 | * @see loadFromFile() |
||
52 | * @see saveToFile() |
||
53 | */ |
||
54 | public $assignmentFile = '@app/rbac/assignments.php'; |
||
55 | /** |
||
56 | * @var string the path of the PHP script that contains the authorization rules. |
||
57 | * This can be either a file path or a [path alias](guide:concept-aliases) to the file. |
||
58 | * Make sure this file is writable by the Web server process if the authorization needs to be changed online. |
||
59 | * @see loadFromFile() |
||
60 | * @see saveToFile() |
||
61 | */ |
||
62 | public $ruleFile = '@app/rbac/rules.php'; |
||
63 | |||
64 | /** |
||
65 | * @var Item[] |
||
66 | */ |
||
67 | protected $items = []; // itemName => item |
||
68 | /** |
||
69 | * @var array |
||
70 | */ |
||
71 | protected $children = []; // itemName, childName => child |
||
72 | /** |
||
73 | * @var array |
||
74 | */ |
||
75 | protected $assignments = []; // userId, itemName => assignment |
||
76 | /** |
||
77 | * @var Rule[] |
||
78 | */ |
||
79 | protected $rules = []; // ruleName => rule |
||
80 | |||
81 | |||
82 | /** |
||
83 | * Initializes the application component. |
||
84 | * This method overrides parent implementation by loading the authorization data |
||
85 | * from PHP script. |
||
86 | */ |
||
87 | 50 | public function init() |
|
95 | |||
96 | /** |
||
97 | * @inheritdoc |
||
98 | */ |
||
99 | 22 | public function checkAccess($userId, $permissionName, $params = []) |
|
109 | |||
110 | /** |
||
111 | * @inheritdoc |
||
112 | */ |
||
113 | 26 | public function getAssignments($userId) |
|
117 | |||
118 | /** |
||
119 | * Performs access check for the specified user. |
||
120 | * This method is internally called by [[checkAccess()]]. |
||
121 | * |
||
122 | * @param string|int $user the user ID. This should can be either an integer or a string representing |
||
123 | * the unique identifier of a user. See [[\yii\web\User::id]]. |
||
124 | * @param string $itemName the name of the operation that need access check |
||
125 | * @param array $params name-value pairs that would be passed to rules associated |
||
126 | * with the tasks and roles assigned to the user. A param with name 'user' is added to this array, |
||
127 | * which holds the value of `$userId`. |
||
128 | * @param Assignment[] $assignments the assignments to the specified user |
||
129 | * @return bool whether the operations can be performed by the user. |
||
130 | */ |
||
131 | 14 | protected function checkAccessRecursive($user, $itemName, $params, $assignments) |
|
132 | { |
||
133 | 14 | if (!isset($this->items[$itemName])) { |
|
134 | 1 | return false; |
|
135 | } |
||
136 | |||
137 | /* @var $item Item */ |
||
138 | 14 | $item = $this->items[$itemName]; |
|
139 | 14 | Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission : $itemName", __METHOD__); |
|
140 | |||
141 | 14 | if (!$this->executeRule($user, $item, $params)) { |
|
142 | 6 | return false; |
|
143 | } |
||
144 | |||
145 | 14 | if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) { |
|
146 | 12 | return true; |
|
147 | } |
||
148 | |||
149 | 13 | foreach ($this->children as $parentName => $children) { |
|
150 | 13 | if (isset($children[$itemName]) && $this->checkAccessRecursive($user, $parentName, $params, $assignments)) { |
|
151 | 13 | return true; |
|
152 | } |
||
153 | } |
||
154 | |||
155 | 3 | return false; |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * @inheritdoc |
||
160 | * @since 2.0.8 |
||
161 | */ |
||
162 | 1 | public function canAddChild($parent, $child) |
|
166 | |||
167 | /** |
||
168 | * @inheritdoc |
||
169 | */ |
||
170 | 44 | public function addChild($parent, $child) |
|
194 | |||
195 | /** |
||
196 | * Checks whether there is a loop in the authorization item hierarchy. |
||
197 | * |
||
198 | * @param Item $parent parent item |
||
199 | * @param Item $child the child item that is to be added to the hierarchy |
||
200 | * @return bool whether a loop exists |
||
201 | */ |
||
202 | 44 | protected function detectLoop($parent, $child) |
|
203 | { |
||
204 | 44 | if ($child->name === $parent->name) { |
|
205 | 1 | return true; |
|
206 | } |
||
207 | 44 | if (!isset($this->children[$child->name], $this->items[$parent->name])) { |
|
208 | 44 | return false; |
|
209 | } |
||
210 | 43 | foreach ($this->children[$child->name] as $grandchild) { |
|
211 | /* @var $grandchild Item */ |
||
212 | 43 | if ($this->detectLoop($parent, $grandchild)) { |
|
213 | 43 | return true; |
|
214 | } |
||
215 | } |
||
216 | |||
217 | 43 | return false; |
|
218 | } |
||
219 | |||
220 | /** |
||
221 | * @inheritdoc |
||
222 | */ |
||
223 | public function removeChild($parent, $child) |
||
224 | { |
||
225 | if (isset($this->children[$parent->name][$child->name])) { |
||
226 | unset($this->children[$parent->name][$child->name]); |
||
227 | $this->saveItems(); |
||
228 | return true; |
||
229 | } |
||
230 | |||
231 | return false; |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * @inheritdoc |
||
236 | */ |
||
237 | public function removeChildren($parent) |
||
238 | { |
||
239 | if (isset($this->children[$parent->name])) { |
||
240 | unset($this->children[$parent->name]); |
||
241 | $this->saveItems(); |
||
242 | return true; |
||
243 | } |
||
244 | |||
245 | return false; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * @inheritdoc |
||
250 | */ |
||
251 | public function hasChild($parent, $child) |
||
255 | |||
256 | /** |
||
257 | * @inheritdoc |
||
258 | */ |
||
259 | 45 | public function assign($role, $userId) |
|
260 | { |
||
261 | 45 | if (!isset($this->items[$role->name])) { |
|
262 | throw new InvalidArgumentException("Unknown role '{$role->name}'."); |
||
263 | 45 | } elseif (isset($this->assignments[$userId][$role->name])) { |
|
264 | throw new InvalidArgumentException("Authorization item '{$role->name}' has already been assigned to user '$userId'."); |
||
265 | } |
||
266 | |||
267 | 45 | $this->assignments[$userId][$role->name] = new Assignment([ |
|
268 | 45 | 'userId' => $userId, |
|
269 | 45 | 'roleName' => $role->name, |
|
270 | 45 | 'createdAt' => time(), |
|
271 | ]); |
||
272 | 45 | $this->saveAssignments(); |
|
273 | |||
274 | 45 | return $this->assignments[$userId][$role->name]; |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * @inheritdoc |
||
279 | */ |
||
280 | public function revoke($role, $userId) |
||
281 | { |
||
282 | if (isset($this->assignments[$userId][$role->name])) { |
||
283 | unset($this->assignments[$userId][$role->name]); |
||
284 | $this->saveAssignments(); |
||
285 | return true; |
||
286 | } |
||
287 | |||
288 | return false; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * @inheritdoc |
||
293 | */ |
||
294 | public function revokeAll($userId) |
||
295 | { |
||
296 | if (isset($this->assignments[$userId]) && is_array($this->assignments[$userId])) { |
||
297 | foreach ($this->assignments[$userId] as $itemName => $value) { |
||
298 | unset($this->assignments[$userId][$itemName]); |
||
299 | } |
||
300 | $this->saveAssignments(); |
||
301 | return true; |
||
302 | } |
||
303 | |||
304 | return false; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * @inheritdoc |
||
309 | */ |
||
310 | public function getAssignment($roleName, $userId) |
||
314 | |||
315 | /** |
||
316 | * @inheritdoc |
||
317 | */ |
||
318 | 4 | public function getItems($type) |
|
319 | { |
||
320 | 4 | $items = []; |
|
321 | |||
322 | 4 | foreach ($this->items as $name => $item) { |
|
323 | /* @var $item Item */ |
||
324 | 4 | if ($item->type == $type) { |
|
325 | 4 | $items[$name] = $item; |
|
326 | } |
||
327 | } |
||
328 | |||
329 | 4 | return $items; |
|
330 | } |
||
331 | |||
332 | |||
333 | /** |
||
334 | * @inheritdoc |
||
335 | */ |
||
336 | 2 | public function removeItem($item) |
|
337 | { |
||
338 | 2 | if (isset($this->items[$item->name])) { |
|
339 | 2 | foreach ($this->children as &$children) { |
|
340 | 1 | unset($children[$item->name]); |
|
341 | } |
||
342 | 2 | foreach ($this->assignments as &$assignments) { |
|
343 | 2 | unset($assignments[$item->name]); |
|
344 | } |
||
345 | 2 | unset($this->items[$item->name]); |
|
346 | 2 | $this->saveItems(); |
|
347 | 2 | $this->saveAssignments(); |
|
348 | 2 | return true; |
|
349 | } |
||
350 | |||
351 | return false; |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * @inheritdoc |
||
356 | */ |
||
357 | 13 | public function getItem($name) |
|
361 | |||
362 | /** |
||
363 | * @inheritdoc |
||
364 | */ |
||
365 | 1 | public function updateRule($name, $rule) |
|
366 | { |
||
367 | 1 | if ($rule->name !== $name) { |
|
368 | 1 | unset($this->rules[$name]); |
|
369 | } |
||
370 | 1 | $this->rules[$rule->name] = $rule; |
|
371 | 1 | $this->saveRules(); |
|
372 | 1 | return true; |
|
373 | } |
||
374 | |||
375 | /** |
||
376 | * @inheritdoc |
||
377 | */ |
||
378 | 45 | public function getRule($name) |
|
382 | |||
383 | /** |
||
384 | * @inheritdoc |
||
385 | */ |
||
386 | 5 | public function getRules() |
|
390 | |||
391 | /** |
||
392 | * @inheritdoc |
||
393 | * The roles returned by this method include the roles assigned via [[$defaultRoles]]. |
||
394 | */ |
||
395 | 2 | public function getRolesByUser($userId) |
|
396 | { |
||
397 | 2 | $roles = $this->getDefaultRoleInstances(); |
|
398 | 2 | foreach ($this->getAssignments($userId) as $name => $assignment) { |
|
399 | 2 | $role = $this->items[$assignment->roleName]; |
|
400 | 2 | if ($role->type === Item::TYPE_ROLE) { |
|
407 | |||
408 | /** |
||
409 | * @inheritdoc |
||
410 | */ |
||
411 | 1 | public function getChildRoles($roleName) |
|
430 | |||
431 | /** |
||
432 | * @inheritdoc |
||
433 | */ |
||
434 | 1 | public function getPermissionsByRole($roleName) |
|
449 | |||
450 | /** |
||
451 | * Recursively finds all children and grand children of the specified item. |
||
452 | * |
||
453 | * @param string $name the name of the item whose children are to be looked for. |
||
454 | * @param array $result the children and grand children (in array keys) |
||
455 | */ |
||
456 | 3 | protected function getChildrenRecursive($name, &$result) |
|
465 | |||
466 | /** |
||
467 | * @inheritdoc |
||
468 | */ |
||
469 | 1 | public function getPermissionsByUser($userId) |
|
476 | |||
477 | /** |
||
478 | * Returns all permissions that are directly assigned to user. |
||
479 | * @param string|int $userId the user ID (see [[\yii\web\User::id]]) |
||
480 | * @return Permission[] all direct permissions that the user has. The array is indexed by the permission names. |
||
481 | * @since 2.0.7 |
||
482 | */ |
||
483 | 1 | protected function getDirectPermissionsByUser($userId) |
|
495 | |||
496 | /** |
||
497 | * Returns all permissions that the user inherits from the roles assigned to him. |
||
498 | * @param string|int $userId the user ID (see [[\yii\web\User::id]]) |
||
499 | * @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names. |
||
500 | * @since 2.0.7 |
||
501 | */ |
||
502 | 1 | protected function getInheritedPermissionsByUser($userId) |
|
522 | |||
523 | /** |
||
524 | * @inheritdoc |
||
525 | */ |
||
526 | 1 | public function getChildren($name) |
|
530 | |||
531 | /** |
||
532 | * @inheritdoc |
||
533 | */ |
||
534 | 3 | public function removeAll() |
|
542 | |||
543 | /** |
||
544 | * @inheritdoc |
||
545 | */ |
||
546 | 1 | public function removeAllPermissions() |
|
550 | |||
551 | /** |
||
552 | * @inheritdoc |
||
553 | */ |
||
554 | 1 | public function removeAllRoles() |
|
558 | |||
559 | /** |
||
560 | * Removes all auth items of the specified type. |
||
561 | * @param int $type the auth item type (either Item::TYPE_PERMISSION or Item::TYPE_ROLE) |
||
562 | */ |
||
563 | 2 | protected function removeAllItems($type) |
|
598 | |||
599 | /** |
||
600 | * @inheritdoc |
||
601 | */ |
||
602 | 1 | public function removeAllRules() |
|
610 | |||
611 | /** |
||
612 | * @inheritdoc |
||
613 | */ |
||
614 | public function removeAllAssignments() |
||
619 | |||
620 | /** |
||
621 | * @inheritdoc |
||
622 | */ |
||
623 | 1 | protected function removeRule($rule) |
|
638 | |||
639 | /** |
||
640 | * @inheritdoc |
||
641 | */ |
||
642 | 46 | protected function addRule($rule) |
|
648 | |||
649 | /** |
||
650 | * @inheritdoc |
||
651 | */ |
||
652 | 6 | protected function updateItem($name, $item) |
|
687 | |||
688 | /** |
||
689 | * @inheritdoc |
||
690 | */ |
||
691 | 47 | protected function addItem($item) |
|
707 | |||
708 | /** |
||
709 | * Loads authorization data from persistent storage. |
||
710 | */ |
||
711 | 50 | protected function load() |
|
761 | |||
762 | /** |
||
763 | * Saves authorization data into persistent storage. |
||
764 | */ |
||
765 | 4 | protected function save() |
|
771 | |||
772 | /** |
||
773 | * Loads the authorization data from a PHP script file. |
||
774 | * |
||
775 | * @param string $file the file path. |
||
776 | * @return array the authorization data |
||
777 | * @see saveToFile() |
||
778 | */ |
||
779 | 50 | protected function loadFromFile($file) |
|
787 | |||
788 | /** |
||
789 | * Saves the authorization data to a PHP script file. |
||
790 | * |
||
791 | * @param array $data the authorization data |
||
792 | * @param string $file the file path. |
||
793 | * @see loadFromFile() |
||
794 | */ |
||
795 | 28 | protected function saveToFile($data, $file) |
|
800 | |||
801 | /** |
||
802 | * Invalidates precompiled script cache (such as OPCache or APC) for the given file. |
||
803 | * @param string $file the file path. |
||
804 | * @since 2.0.9 |
||
805 | */ |
||
806 | 28 | protected function invalidateScriptCache($file) |
|
815 | |||
816 | /** |
||
817 | * Saves items data into persistent storage. |
||
818 | */ |
||
819 | 48 | protected function saveItems() |
|
841 | |||
842 | /** |
||
843 | * Saves assignments data into persistent storage. |
||
844 | */ |
||
845 | 46 | protected function saveAssignments() |
|
856 | |||
857 | /** |
||
858 | * Saves rules data into persistent storage. |
||
859 | */ |
||
860 | 47 | protected function saveRules() |
|
868 | |||
869 | /** |
||
870 | * @inheritdoc |
||
871 | * @since 2.0.7 |
||
872 | */ |
||
873 | 1 | public function getUserIdsByRole($roleName) |
|
885 | } |
||
886 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.