ControllerParser::createRouteMethod()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 7.2944

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 14
ccs 9
cts 11
cp 0.8182
rs 8.8333
cc 7
nc 6
nop 12
crap 7.2944

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\exceptions\ParserException;
6
use Ubiquity\orm\parser\Reflexion;
7
use Ubiquity\utils\base\UString;
8
use Ubiquity\cache\ClassUtils;
9
use Ubiquity\annotations\AnnotationsEngineInterface;
10
use Ubiquity\exceptions\RouterException;
11
12
/**
13
 * Scans a controller to detect routes defined by annotations or attributes.
14
 * Ubiquity\cache\parser$ControllerParser
15
 * This class is part of Ubiquity
16
 *
17
 * @author jcheron <[email protected]>
18
 * @version 1.1.1
19
 *
20
 */
21
class ControllerParser {
22
	use ControllerParserPathTrait;
23
	
24
	const HTTP_METHODS=['head','get','post','patch','put','delete','options','connect'];
25
	
26
	private string $controllerClass;
27
	private $mainRouteClass;
28
	private array $routesMethods = [ ];
29
	private bool $rest = false;
30
	private bool $silent=false;
31
	private static array $excludeds = [ '__construct','isValid','initialize','finalize','onInvalidControl','loadView','forward','redirectToRoute' ];
32
	
33
	
34
	/**
35
	 *
36
	 * @var AnnotationsEngineInterface
37
	 */
38
	private $annotsEngine;
39
	
40 17
	public function __construct(AnnotationsEngineInterface $annotsEngine) {
41 17
		$this->annotsEngine = $annotsEngine;
42
	}
43
	
44 17
	public function parse($controllerClass) {
45 17
		$automated = false;
46 17
		$inherited = false;
47 17
		$this->controllerClass = $controllerClass;
48 17
		$restAnnotsClass = [ ];
49 17
		$reflect = new \ReflectionClass ( $controllerClass );
50 17
		if (! $reflect->isAbstract () && $reflect->isSubclassOf ( \Ubiquity\controllers\Controller::class )) {
51
			try {
52 17
				$annotsClass = Reflexion::getAnnotationClass ( $controllerClass, 'route' );
53 17
				$restAnnotsClass = Reflexion::getAnnotationClass ( $controllerClass, 'rest' );
54
			} catch ( \Exception $e ) {
55
				// When controllerClass generates an exception
56
			}
57 17
			$this->rest = \count ( $restAnnotsClass ) > 0;
58 17
			if (isset ( $annotsClass ) && \count ( $annotsClass ) > 0) {
59 17
				$this->mainRouteClass = $annotsClass [0];
60 17
				$inherited = $this->mainRouteClass->inherited;
61 17
				$automated = $this->mainRouteClass->automated;
62
			}
63 17
			$methods = Reflexion::getMethods ( $controllerClass, \ReflectionMethod::IS_PUBLIC );
64 17
			$this->parseMethods ( $methods, $controllerClass, $inherited, $automated );
65
		}
66
	}
67
	
68 17
	private function parseMethods($methods, $controllerClass, $inherited, $automated) {
69 17
		foreach ( $methods as $method ) {
70 17
			if ($method->getDeclaringClass ()->getName () === $controllerClass || $inherited) {
71
				try {
72 17
					$annots = Reflexion::getAnnotationsMethod ( $controllerClass, $method->name, [ 'route','get','post','patch','put','delete','options' ] );
73 17
					if (\count ( $annots ) > 0) {
74 17
						foreach ( $annots as $annot ) {
75 17
							$this->parseAnnot ( $annot, $method );
76
						}
77 17
						$this->routesMethods [$method->name] = [ 'annotations' => $annots,'method' => $method ];
78
					} else {
79 17
						if ($automated && $this->isRoutable($method)){
80 17
							$this->routesMethods [$method->name] = [ 'annotations' => $this->generateRouteAnnotationFromMethod ( $method ),'method' => $method ];
81
						}
82
					}
83 17
				} catch ( \Exception $e ) {
84 17
					if (!$this->silent && $e instanceof ParserException){
85
						throw $e;
86
					}
87
					// When controllerClass generates an exception
88
				}
89
			}
90
		}
91
	}
92
93 17
	private function isRoutable(\ReflectionMethod $method):bool{
94 17
		return $method->class !== 'Ubiquity\\controllers\\Controller'
95 17
			&& \array_search ( $method->name, self::$excludeds ) === false
96 17
			&& ! UString::startswith ( $method->name, '_' )
97 17
			&& Reflexion::getAnnotationsMethod($method->class,$method->name,'noRoute')===false;
98
	}
99
	
100 17
	private function parseAnnot(&$annot, $method) {
101 17
		if (UString::isNull ( $annot->path )) {
102 17
			$newAnnot = $this->generateRouteAnnotationFromMethod ( $method );
103 17
			$annot->path = $newAnnot [0]->path;
104
		} else {
105 17
			$annot->path = $this->parseMethodPath ( $method, $annot->path );
106
		}
107
	}
108
	
109 17
	private function generateRouteAnnotationFromMethod(\ReflectionMethod $method): array {
110 17
		return [ $this->annotsEngine->getAnnotation ( null, 'route', [ 'path' => self::getPathFromMethod ( $method ) ] ) ];
111
	}
112
	
113 17
	private static function generateRouteName(string $controllerName,string $action): string {
114 17
		$ctrl=\str_ireplace('controller','',ClassUtils::getClassSimpleName ( $controllerName ));
115 17
		return \lcfirst($ctrl) . '.' . $action;
116
	}
117
	
118 17
	public function asArray(): array {
119 17
		$result = [ ];
120 17
		$prefix = '';
121 17
		$httpMethods = false;
122 17
		if ($this->mainRouteClass) {
123 17
			if (isset ( $this->mainRouteClass->path )) {
124 17
				$this->mainRouteClass->path=self::parseMainPath($this->mainRouteClass->path,$this->controllerClass);
125 17
				$prefix = $this->mainRouteClass->path;
126
			}
127 17
			if (isset ( $this->mainRouteClass->methods )) {
128
				$httpMethods = $this->mainRouteClass->methods;
129
				if ($httpMethods !== null) {
130
					if (\is_string ( $httpMethods ))
131
						$httpMethods = [ $httpMethods ];
132
				}
133
			}
134
		}
135 17
		foreach ( $this->routesMethods as $method => $arrayAnnotsMethod ) {
136 17
			$routeAnnotations = $arrayAnnotsMethod ['annotations'];
137
			
138 17
			foreach ( $routeAnnotations as $routeAnnotation ) {
139 17
				$params = [ 'path' => $routeAnnotation->path,'methods' => $routeAnnotation->methods,'name' => $routeAnnotation->name,'cache' => $routeAnnotation->cache,'duration' => $routeAnnotation->duration,'requirements' => $routeAnnotation->requirements,'priority' => $routeAnnotation->priority ];
140 17
				self::parseRouteArray ( $result, $this->controllerClass, $params, $arrayAnnotsMethod ['method'], $method, $prefix, $httpMethods );
141
			}
142
		}
143 17
		self::$mainParams=null;
144 17
		return $result;
145
	}
146
	
147 47
	public static function parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix = '', $httpMethods = NULL) {
148 47
		if (! isset ( $routeArray ['path'] )) {
149
			$routeArray ['path'] = self::getPathFromMethod ( $method );
150
		}
151 47
		$pathParameters = self::addParamsPath ( $routeArray ['path'], $method, $routeArray ['requirements'] );
152 47
		$name = $routeArray ['name'];
153 47
		if (! isset ( $name )) {
154 17
			$name = self::generateRouteName($controllerClass,$methodName);
155
		}
156 47
		$cache = $routeArray ['cache'];
157 47
		$duration = $routeArray ['duration'];
158 47
		$path = $pathParameters ['path'];
159 47
		$parameters = $pathParameters ['parameters'];
160 47
		$priority = $routeArray ['priority'];
161 47
		$callback = $routeArray ['callback'] ?? null;
162 47
		$isRoot=false;
163 47
		$path = self::cleanpath ( $prefix, $path ,$isRoot);
164 47
		if (isset ( $routeArray ['methods'] ) && \is_array ( $routeArray ['methods'] )) {
165 17
			self::createRouteMethod ( $result, $controllerClass, $path, $routeArray ['methods'], $methodName, $parameters, $name, $cache, $duration, $priority, $callback , $isRoot);
166 47
		} elseif (\is_array ( $httpMethods )) {
167
			self::createRouteMethod ( $result, $controllerClass, $path, $httpMethods, $methodName, $parameters, $name, $cache, $duration, $priority, $callback , $isRoot);
168
		} else {
169 47
			$v = [ 'controller' => $controllerClass,'action' => $methodName,'parameters' => $parameters,'name' => $name,'cache' => $cache,'duration' => $duration,'priority' => $priority];
170 47
			if (isset ( $callback )) {
171 1
				$v ['callback'] = $callback;
172
			}
173 47
			if(!$isRoot && isset(self::$mainParams) && \count(self::$mainParams)>0){
174 17
				$v['main.params']=self::$mainParams;
175
			}
176 47
			$result [$path] = $v;
177
		}
178
	}
179
	
180 17
	private static function createRouteMethod(&$result, $controllerClass, $path, $httpMethods, $method, $parameters, $name, $cache, $duration, $priority, $callback = null,$isRoot=false) {
181 17
		foreach ( $httpMethods as $httpMethod ) {
182 17
			$httpMethod=\strtolower($httpMethod);
183 17
			if(\array_search($httpMethod, self::HTTP_METHODS)===false){
184
				throw new RouterException("$httpMethod is not a valid HTTP method!");
185
			}
186 17
			$v = [ 'controller' => $controllerClass,'action' => $method,'parameters' => $parameters,'name' => $name,'cache' => $cache,'duration' => $duration,'priority' => $priority ];
187 17
			if (isset ( $callback )) {
188
				$v ['callback'] = $callback;
189
			}
190 17
			if(!$isRoot && isset(self::$mainParams) && \count(self::$mainParams)>0){
191 17
				$v['main.params']=self::$mainParams;
192
			}
193 17
			$result [$path] [$httpMethod] = $v;
194
		}
195
	}
196
	
197 17
	public function isRest(): bool {
198 17
		return $this->rest;
199
	}
200
	
201
	/**
202
	 * @param bool $silent
203
	 */
204 17
	public function setSilent(bool $silent): void {
205 17
		$this->silent = $silent;
206
	}
207
}
208