Passed
Push — main ( 6cee10...25dcc1 )
by Jean-Christophe
02:23
created

AclControllerParser   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Test Coverage

Coverage 87.18%

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 73
dl 0
loc 116
ccs 68
cts 78
cp 0.8718
rs 8.96
c 4
b 0
f 1
wmc 43

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A init() 0 2 1
B addAllows() 0 12 11
B parseMethods() 0 19 10
A save() 0 3 1
B parse() 0 20 8
B parseMethod() 0 29 11

How to fix   Complexity   

Complex Class

Complex classes like AclControllerParser 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 AclControllerParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Ubiquity\security\acl\cache;
3
4
use Ubiquity\controllers\Controller;
5
use Ubiquity\orm\parser\Reflexion;
6
use Ubiquity\security\acl\AclManager;
7
use Ubiquity\cache\ClassUtils;
8
use Ubiquity\exceptions\AclException;
9
10
/**
11
 * Ubiquity\security\acl\cache$AclControllerParser
12
 * This class is part of Ubiquity
13
 *
14
 * @author jc
15
 * @version 1.0.0
16
 *
17
 */
18
class AclControllerParser {
19
20
	protected $controllerClass;
21
22
	protected $mainResource;
23
24
	protected $mainPermission;
25
26
	protected $permissionMap;
27
28 2
	public function __construct() {
29 2
		$this->permissionMap = new PermissionsMap();
30 2
	}
31
32 2
	public function init() {
33 2
		$this->permissionMap->init();
34 2
	}
35
36 2
	protected function parseMethods($methods) {
37 2
		$hasPermission = false;
38 2
		$controllerClass = $this->controllerClass;
39 2
		$controller = ClassUtils::getClassSimpleName($controllerClass);
40 2
		foreach ($methods as $method) {
41 2
			$this->parseMethod($method, $hasPermission, $controller);
42
		}
43 2
		if ($hasPermission || $this->mainResource != null || $this->mainPermission != null) {
44 2
			$permission = 'ALL';
45 2
			$resource = $this->mainResource ? $this->mainResource->name : $controller;
46 2
			$this->permissionMap->addAction($controller, '*', $resource, $this->mainPermission ? $this->mainPermission->name : 'ALL');
47 2
			AclManager::addResource($resource, $controller . '.*');
48 2
			if (isset($this->mainPermission)) {
49
				$permission = $this->mainPermission->name;
50
				AclManager::addPermission($this->mainPermission->name, ($this->mainPermission->level) ?? 0);
51
			}
52 2
			$annotsAllow = Reflexion::getAnnotationClass($controllerClass, '@allow');
53 2
			if (\is_array($annotsAllow) && \count($annotsAllow) > 0) {
54
				$this->addAllows($annotsAllow, $controller, '*', $resource, $permission);
55
			}
56
		}
57 2
	}
58
59 2
	protected function parseMethod(\ReflectionMethod $method, bool &$hasPermission, $controller) {
60 2
		$action = $method->name;
61 2
		$permission = NULL;
62 2
		$resource = NULL;
63 2
		$controllerClass = $this->controllerClass;
64 2
		if ($method->getDeclaringClass()->getName() === $controllerClass) {
65
			try {
66 2
				$annotResource = Reflexion::getAnnotationMethod($controllerClass, $action, '@resource');
67 2
				$annotPermission = Reflexion::getAnnotationMethod($controllerClass, $action, '@permission');
68 2
				if ($annotResource) {
69 2
					$resource = $annotResource->name;
70 2
					AclManager::addResource($annotResource->name, $controller . '.' . $action);
71
				}
72 2
				if ($annotPermission) {
73 2
					$permission = $annotPermission->name;
74 2
					AclManager::addPermission($annotPermission->name, $annotPermission->level ?? 0);
75 2
					$resource ??= $this->mainResource ? $this->mainResource->name : NULL;
76 2
					$hasPermission = true;
77
				} else {
78 2
					$resource ??= $this->mainResource ? $this->mainResource->name : ($controller . '.' . $action);
79
				}
80 2
				$annotsAllow = Reflexion::getAnnotationsMethod($controllerClass, $action, '@allow');
81 2
				if (\is_array($annotsAllow) && \count($annotsAllow) > 0) {
82 2
					$this->addAllows($annotsAllow, $controller, $action, $resource, $permission);
83
				}
84 2
				if ($permission !== null && $resource !== null) {
85 2
					$this->permissionMap->addAction($controllerClass, $action, $resource, $permission);
86
				}
87
			} catch (\Exception $e) {
88
				// Exception in controller code
89
			}
90
		}
91 2
	}
92
93 2
	protected function addAllows($annotsAllow, $controller, $action, &$resource, &$permission) {
94 2
		foreach ($annotsAllow as $annotAllow) {
95 2
			if (isset($annotAllow->resource) && isset($resource) && $resource !== $annotAllow->resource && $permission != null) {
96
				throw new AclException("Resources {$resource} and {$annotAllow->resource} are in conflict for action {$controller}.{$action}");
97
			}
98 2
			if (isset($annotAllow->permission) && isset($permission) && $permission !== $annotAllow->permission) {
99
				throw new AclException("Permissions {$permission} and {$annotAllow->permission} are in conflict for action {$controller}.{$action}");
100
			}
101 2
			if ($permission === null && $annotAllow->permission === null) {
102 2
				$resource = $controller . '.' . $action;
103
			}
104 2
			AclManager::addAndAllow($annotAllow->role, $resource = $annotAllow->resource ?? $resource, $permission = $annotAllow->permission ?? $permission);
105
		}
106 2
	}
107
108 2
	public function parse($controllerClass) {
109 2
		$this->controllerClass = $controllerClass;
110 2
		$reflect = new \ReflectionClass($controllerClass);
111 2
		if (! $reflect->isAbstract() && $reflect->isSubclassOf(Controller::class)) {
112
			try {
113 2
				$annotsResource = Reflexion::getAnnotationClass($controllerClass, '@resource');
114 2
				$annotsPermission = Reflexion::getAnnotationClass($controllerClass, '@permission');
115 2
				$annotAllows = Reflexion::getAnnotationClass($controllerClass, '@allow');
116
			} catch (\Exception $e) {
117
				// When controllerClass generates an exception
118
			}
119 2
			$this->mainResource = $annotsResource[0] ?? null;
120 2
			$this->mainPermission = $annotsPermission[0] ?? null;
121 2
			if (\is_array($annotAllows) && \count($annotAllows) > 0) {
122
				$resource = $this->mainResource ? $this->mainResource->name : $reflect->getShortName();
123
				$permission = $this->mainPermission ? $this->mainPermission->name : 'ALL';
124
				$this->addAllows($annotAllows, $controllerClass, null, $resource, $permission);
125
			}
126 2
			$methods = Reflexion::getMethods($controllerClass, \ReflectionMethod::IS_PUBLIC);
127 2
			$this->parseMethods($methods);
128
		}
129 2
	}
130
131 2
	public function save() {
132 2
		$this->permissionMap->save();
133 2
		AclManager::saveAll();
134 2
	}
135
}
136
137