Passed
Push — master ( aa7ab8...ee1769 )
by Jean-Christophe
01:33
created

ControllerParser   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 121
dl 0
loc 181
rs 8.5599
c 0
b 0
f 0
wmc 48

10 Methods

Rating   Name   Duplication   Size   Complexity  
A parse() 0 22 5
A createRouteMethod() 0 3 2
A isRest() 0 2 1
B parseMethods() 0 17 11
A parseAnnot() 0 6 2
B asArray() 0 28 8
A generateRouteAnnotationFromMethod() 0 4 1
B addParamsPath() 0 25 7
A parseRouteArray() 0 21 6
A scanParam() 0 17 5

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Ubiquity\cache\parser;
4
5
use Ubiquity\orm\parser\Reflexion;
6
use Ubiquity\utils\base\UString;
7
use Ubiquity\annotations\router\RouteAnnotation;
8
use Ubiquity\cache\ClassUtils;
9
use Ubiquity\utils\base\UArray;
10
11
/**
12
 * Scans a controller to detect routes defined by annotations 
13
 * @author jcheron <[email protected]>
14
 * @version 1.0.2
15
 */
16
class ControllerParser {
17
	use ControllerParserPathTrait;
18
	
19
	private $controllerClass;
20
	private $mainRouteClass;
21
	private $routesMethods=[ ];
22
	private $rest=false;
23
	private static $excludeds=[ "__construct","isValid","initialize","finalize","onInvalidControl","loadView","forward","redirectToRoute" ];
24
25
	public function parse($controllerClass) {
26
		$automated=false;
27
		$inherited=false;
28
		$this->controllerClass=$controllerClass;
29
		$restAnnotsClass=[];
30
		$reflect=new \ReflectionClass($controllerClass);
31
		if (!$reflect->isAbstract() && $reflect->isSubclassOf("Ubiquity\controllers\Controller")) {
32
			$instance=new $controllerClass();
33
			try{
34
				$annotsClass=Reflexion::getAnnotationClass($controllerClass, "@route");
35
				$restAnnotsClass=Reflexion::getAnnotationClass($controllerClass, "@rest");
36
			}catch (\Exception $e){
37
				//When controllerClass generates an exception
38
			}
39
			$this->rest=\sizeof($restAnnotsClass) > 0;
40
			if (\sizeof($annotsClass) > 0) {
41
				$this->mainRouteClass=$annotsClass[0];
42
				$inherited=$this->mainRouteClass->inherited;
43
				$automated=$this->mainRouteClass->automated;
44
			}
45
			$methods=Reflexion::getMethods($instance, \ReflectionMethod::IS_PUBLIC);
46
			$this->parseMethods($methods, $controllerClass, $inherited, $automated);
47
		}
48
	}
49
	
50
	private function parseMethods($methods,$controllerClass,$inherited,$automated){
51
		foreach ( $methods as $method ) {
52
			if ($method->getDeclaringClass()->getName() === $controllerClass || $inherited) {
53
				try{
54
					$annots=Reflexion::getAnnotationsMethod($controllerClass, $method->name, ["@route","@get","@post"]);
55
					if (sizeof($annots)>0) {
56
						foreach ( $annots as $annot ) {
57
							$this->parseAnnot($annot, $method);
58
						}
59
						$this->routesMethods[$method->name]=[ "annotations" => $annots,"method" => $method ];
60
					} else {
61
						if ($automated) {
62
							if ($method->class !== 'Ubiquity\\controllers\\Controller' && \array_search($method->name, self::$excludeds) === false && !UString::startswith($method->name, "_"))
63
								$this->routesMethods[$method->name]=[ "annotations" => $this->generateRouteAnnotationFromMethod($method),"method" => $method ];
64
						}
65
					}
66
				}catch(\Exception $e){
67
					//When controllerClass generates an exception
68
				}
69
			}
70
		}
71
	}
72
	
73
	private function parseAnnot(&$annot,$method){
74
		if (UString::isNull($annot->path)) {
75
			$newAnnot=$this->generateRouteAnnotationFromMethod($method);
76
			$annot->path=$newAnnot[0]->path;
77
		}else{
78
			$annot->path=$this->parseMethodPath($method, $annot->path);
79
		}
80
	}
81
82
	private function generateRouteAnnotationFromMethod(\ReflectionMethod $method) {
83
		$annot=new RouteAnnotation();
84
		$annot->path=self::getPathFromMethod($method);
85
		return [ $annot ];
86
	}
87
88
	public function asArray() {
89
		$result=[ ];
90
		$prefix="";
91
		$httpMethods=false;
92
		if ($this->mainRouteClass) {
93
			if (isset($this->mainRouteClass->path))
94
				$prefix=$this->mainRouteClass->path;
95
			if (isset($this->mainRouteClass->methods)) {
96
				$httpMethods=$this->mainRouteClass->methods;
97
				if ($httpMethods !== null) {
98
					if (\is_string($httpMethods))
99
						$httpMethods=[ $httpMethods ];
100
				}
101
			}
102
		}
103
		foreach ( $this->routesMethods as $method => $arrayAnnotsMethod ) {
104
			$routeAnnotations=$arrayAnnotsMethod["annotations"];
105
106
			foreach ( $routeAnnotations as $routeAnnotation ) {
107
				$params=[ "path" => $routeAnnotation->path,"methods" => $routeAnnotation->methods,"name" => $routeAnnotation->name,"cache" => $routeAnnotation->cache,"duration" => $routeAnnotation->duration,"requirements" => $routeAnnotation->requirements,"priority"=>$routeAnnotation->priority ];
108
				self::parseRouteArray($result, $this->controllerClass, $params, $arrayAnnotsMethod["method"], $method, $prefix, $httpMethods);
109
			}
110
		}
111
		uasort($result, function ($item1, $item2) {
112
			return UArray::getRecursive($item2,"priority",0) <=> UArray::getRecursive($item1,"priority",0);
113
		});
114
		UArray::removeRecursive($result,"priority");
115
		return $result;
116
	}
117
118
	public static function parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix="", $httpMethods=NULL) {
119
		if (!isset($routeArray["path"])) {
120
			$routeArray["path"]=self::getPathFromMethod($method);
121
		}
122
		$pathParameters=self::addParamsPath($routeArray["path"], $method, $routeArray["requirements"]);
123
		$name=$routeArray["name"];
124
		if (!isset($name)) {
125
			$name=UString::cleanAttribute(ClassUtils::getClassSimpleName($controllerClass) . "_" . $methodName);
126
		}
127
		$cache=$routeArray["cache"];
128
		$duration=$routeArray["duration"];
129
		$path=$pathParameters["path"];
130
		$parameters=$pathParameters["parameters"];
131
		$priority=$routeArray["priority"];
132
		$path=self::cleanpath($prefix, $path);
133
		if (isset($routeArray["methods"]) && \is_array($routeArray["methods"])) {
134
			self::createRouteMethod($result, $controllerClass, $path, $routeArray["methods"], $methodName, $parameters, $name, $cache, $duration,$priority);
135
		} elseif (\is_array($httpMethods)) {
136
			self::createRouteMethod($result, $controllerClass, $path, $httpMethods, $methodName, $parameters, $name, $cache, $duration,$priority);
137
		} else {
138
			$result[$path]=[ "controller" => $controllerClass,"action" => $methodName,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration,"priority"=>$priority];
139
		}
140
	}
141
142
	public static function addParamsPath($path, \ReflectionMethod $method, $requirements) {
143
		$parameters=[ ];
144
		$hasOptional=false;
145
		preg_match_all('@\{(\.\.\.|\~)?(.+?)\}@s', $path, $matches);
146
		if (isset($matches[2]) && \sizeof($matches[2]) > 0) {
147
			$path=\preg_quote($path);
148
			$params=Reflexion::getMethodParameters($method);
149
			$index=0;
150
			foreach ( $matches[2] as $paramMatch ) {
151
				$find=\array_search($paramMatch, $params);
152
				if ($find !== false) {
153
					$requirement='.+?';
154
					if (isset($requirements[$paramMatch])) {
155
						$requirement=$requirements[$paramMatch];
156
					}
157
					self::scanParam($parameters, $hasOptional, $matches, $index, $paramMatch, $find, $path, $requirement);
158
				} else {
159
					throw new \Exception("{$paramMatch} is not a parameter of the method " . $method->name);
160
				}
161
				$index++;
162
			}
163
		}
164
		if ($hasOptional)
165
			$path.="/(.*?)";
166
		return [ "path" => $path,"parameters" => $parameters ];
167
	}
168
169
	private static function scanParam(&$parameters, &$hasOptional, $matches, $index, $paramMatch, $find, &$path, $requirement) {
170
		$toReplace=true;
171
		if (isset($matches[1][$index])) {
172
			if ($matches[1][$index] === "...") {
173
				$parameters[]="*";
174
				$path=\str_replace("\{\.\.\." . $paramMatch . "\}", "(.*?)", $path);
175
				$toReplace=false;
176
			} elseif ($matches[1][$index] === "~") {
177
				$parameters[]="~" . $find;
178
				$path=\str_replace("\{~" . $paramMatch . "\}", "", $path);
179
				$hasOptional=true;
180
				$toReplace=false;
181
			}
182
		} 
183
		if($toReplace) {
184
			$parameters[]=$find;
185
			$path=\str_replace("\{" . $paramMatch . "\}", "({$requirement})", $path);
186
		}
187
	}
188
189
	private static function createRouteMethod(&$result, $controllerClass, $path, $httpMethods, $method, $parameters, $name, $cache, $duration,$priority) {
190
		foreach ( $httpMethods as $httpMethod ) {
191
			$result[$path][$httpMethod]=[ "controller" => $controllerClass,"action" => $method,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration,"priority"=>$priority ];
192
		}
193
	}
194
195
	public function isRest() {
196
		return $this->rest;
197
	}
198
}
199