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

ControllerParser::scanParam()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 8
nop 8
dl 0
loc 17
rs 9.4888
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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