Passed
Push — master ( 5a27b6...d7396e )
by Jean-Christophe
02:39
created

ControllerParser::createRouteMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 10
dl 0
loc 3
rs 10
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 jc
14
 * @version 1.0.1
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=[];$annotsClass=[];
0 ignored issues
show
Unused Code introduced by
The assignment to $annotsClass is dead and can be removed.
Loading history...
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
			foreach ( $methods as $method ) {
47
				if ($method->getDeclaringClass()->getName() === $controllerClass || $inherited) {
48
					try{
49
						$annots=Reflexion::getAnnotationsMethod($controllerClass, $method->name, ["@route","@get","@post"]);
50
						if (sizeof($annots)>0) {
51
							foreach ( $annots as $annot ) {
52
								if (UString::isNull($annot->path)) {
53
									$newAnnot=$this->generateRouteAnnotationFromMethod($method);
54
									$annot->path=$newAnnot[0]->path;
55
								}else{
56
									$annot->path=$this->parseMethodPath($method, $annot->path);
57
								}
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
74
	private function generateRouteAnnotationFromMethod(\ReflectionMethod $method) {
75
		$annot=new RouteAnnotation();
76
		$annot->path=self::getPathFromMethod($method);
77
		return [ $annot ];
78
	}
79
80
	public function asArray() {
81
		$result=[ ];
82
		$prefix="";
83
		$httpMethods=false;
84
		if ($this->mainRouteClass) {
85
			if (isset($this->mainRouteClass->path))
86
				$prefix=$this->mainRouteClass->path;
87
			if (isset($this->mainRouteClass->methods)) {
88
				$httpMethods=$this->mainRouteClass->methods;
89
				if ($httpMethods !== null) {
90
					if (\is_string($httpMethods))
91
						$httpMethods=[ $httpMethods ];
92
				}
93
			}
94
		}
95
		foreach ( $this->routesMethods as $method => $arrayAnnotsMethod ) {
96
			$routeAnnotations=$arrayAnnotsMethod["annotations"];
97
98
			foreach ( $routeAnnotations as $routeAnnotation ) {
99
				$params=[ "path" => $routeAnnotation->path,"methods" => $routeAnnotation->methods,"name" => $routeAnnotation->name,"cache" => $routeAnnotation->cache,"duration" => $routeAnnotation->duration,"requirements" => $routeAnnotation->requirements,"priority"=>$routeAnnotation->priority ];
100
				self::parseRouteArray($result, $this->controllerClass, $params, $arrayAnnotsMethod["method"], $method, $prefix, $httpMethods);
101
			}
102
		}
103
		uasort($result, function ($item1, $item2) {
104
			return UArray::getRecursive($item2,"priority",0) <=> UArray::getRecursive($item1,"priority",0);
105
		});
106
		UArray::removeRecursive($result,"priority");
107
		return $result;
108
	}
109
110
	public static function parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix="", $httpMethods=NULL) {
111
		if (!isset($routeArray["path"])) {
112
			$routeArray["path"]=self::getPathFromMethod($method);
113
		}
114
		$pathParameters=self::addParamsPath($routeArray["path"], $method, $routeArray["requirements"]);
115
		$name=$routeArray["name"];
116
		if (!isset($name)) {
117
			$name=UString::cleanAttribute(ClassUtils::getClassSimpleName($controllerClass) . "_" . $methodName);
118
		}
119
		$cache=$routeArray["cache"];
120
		$duration=$routeArray["duration"];
121
		$path=$pathParameters["path"];
122
		$parameters=$pathParameters["parameters"];
123
		$priority=$routeArray["priority"];
124
		$path=self::cleanpath($prefix, $path);
125
		if (isset($routeArray["methods"]) && \is_array($routeArray["methods"])) {
126
			self::createRouteMethod($result, $controllerClass, $path, $routeArray["methods"], $methodName, $parameters, $name, $cache, $duration,$priority);
127
		} elseif (\is_array($httpMethods)) {
128
			self::createRouteMethod($result, $controllerClass, $path, $httpMethods, $methodName, $parameters, $name, $cache, $duration,$priority);
129
		} else {
130
			$result[$path]=[ "controller" => $controllerClass,"action" => $methodName,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration,"priority"=>$priority];
131
		}
132
	}
133
134
	public static function addParamsPath($path, \ReflectionMethod $method, $requirements) {
135
		$parameters=[ ];
136
		$hasOptional=false;
137
		preg_match_all('@\{(\.\.\.|\~)?(.+?)\}@s', $path, $matches);
138
		if (isset($matches[2]) && \sizeof($matches[2]) > 0) {
139
			$path=\preg_quote($path);
140
			$params=Reflexion::getMethodParameters($method);
141
			$index=0;
142
			foreach ( $matches[2] as $paramMatch ) {
143
				$find=\array_search($paramMatch, $params);
144
				if ($find !== false) {
145
					$requirement='.+?';
146
					if (isset($requirements[$paramMatch])) {
147
						$requirement=$requirements[$paramMatch];
148
					}
149
					self::scanParam($parameters, $hasOptional, $matches, $index, $paramMatch, $find, $path, $requirement);
150
				} else {
151
					throw new \Exception("{$paramMatch} is not a parameter of the method " . $method->name);
152
				}
153
				$index++;
154
			}
155
		}
156
		if ($hasOptional)
157
			$path.="/(.*?)";
158
		return [ "path" => $path,"parameters" => $parameters ];
159
	}
160
161
	private static function scanParam(&$parameters, &$hasOptional, $matches, $index, $paramMatch, $find, &$path, $requirement) {
162
		$toReplace=true;
163
		if (isset($matches[1][$index])) {
164
			if ($matches[1][$index] === "...") {
165
				$parameters[]="*";
166
				$path=\str_replace("\{\.\.\." . $paramMatch . "\}", "(.*?)", $path);
167
				$toReplace=false;
168
			} elseif ($matches[1][$index] === "~") {
169
				$parameters[]="~" . $find;
170
				$path=\str_replace("\{~" . $paramMatch . "\}", "", $path);
171
				$hasOptional=true;
172
				$toReplace=false;
173
			}
174
		} 
175
		if($toReplace) {
176
			$parameters[]=$find;
177
			$path=\str_replace("\{" . $paramMatch . "\}", "({$requirement})", $path);
178
		}
179
	}
180
181
	private static function createRouteMethod(&$result, $controllerClass, $path, $httpMethods, $method, $parameters, $name, $cache, $duration,$priority) {
182
		foreach ( $httpMethods as $httpMethod ) {
183
			$result[$path][$httpMethod]=[ "controller" => $controllerClass,"action" => $method,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration,"priority"=>$priority ];
184
		}
185
	}
186
187
	public function isRest() {
188
		return $this->rest;
189
	}
190
}
191