Test Failed
Push — master ( cf3dbd...f03535 )
by Jean-Christophe
27:09
created

ControllerParser::createRouteMethod()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 7.5375

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 10
c 2
b 0
f 1
dl 0
loc 14
ccs 7
cts 9
cp 0.7778
rs 8.8333
cc 7
nc 6
nop 12
crap 7.5375

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 17
	}
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 17
	}
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 17
						}
82
					}
83
				} catch ( \Exception $e ) {
84
					if (!$this->silent && $e instanceof ParserException){
85
						throw $e;
86
					}
87
					// When controllerClass generates an exception
88
				}
89
			}
90
		}
91
	}
92 17
93
	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 17
	
100
	private function parseAnnot(&$annot, $method) {
101 17
		if (UString::isNull ( $annot->path )) {
102
			$newAnnot = $this->generateRouteAnnotationFromMethod ( $method );
103 17
			$annot->path = $newAnnot [0]->path;
104 17
		} else {
105
			$annot->path = $this->parseMethodPath ( $method, $annot->path );
106
		}
107 17
	}
108 17
	
109 17
	private function generateRouteAnnotationFromMethod(\ReflectionMethod $method): array {
110
		return [ $this->annotsEngine->getAnnotation ( null, 'route', [ 'path' => self::getPathFromMethod ( $method ) ] ) ];
111
	}
112 17
	
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 17
	}
117 17
	
118 17
	public function asArray(): array {
119 17
		$result = [ ];
120
		$prefix = '';
121 17
		$httpMethods = false;
122
		if ($this->mainRouteClass) {
123
			if (isset ( $this->mainRouteClass->path )) {
124
				$this->mainRouteClass->path=self::parseMainPath($this->mainRouteClass->path,$this->controllerClass);
125
				$prefix = $this->mainRouteClass->path;
126
			}
127
			if (isset ( $this->mainRouteClass->methods )) {
128
				$httpMethods = $this->mainRouteClass->methods;
129 17
				if ($httpMethods !== null) {
130 17
					if (\is_string ( $httpMethods ))
131
						$httpMethods = [ $httpMethods ];
132 17
				}
133 17
			}
134 17
		}
135
		foreach ( $this->routesMethods as $method => $arrayAnnotsMethod ) {
136
			$routeAnnotations = $arrayAnnotsMethod ['annotations'];
137 17
			
138 17
			foreach ( $routeAnnotations as $routeAnnotation ) {
139
				$params = [ 'path' => $routeAnnotation->path,'methods' => $routeAnnotation->methods,'name' => $routeAnnotation->name,'cache' => $routeAnnotation->cache,'duration' => $routeAnnotation->duration,'requirements' => $routeAnnotation->requirements,'priority' => $routeAnnotation->priority ];
140
				self::parseRouteArray ( $result, $this->controllerClass, $params, $arrayAnnotsMethod ['method'], $method, $prefix, $httpMethods );
141 42
			}
142 42
		}
143
		self::$mainParams=null;
144
		return $result;
145 42
	}
146 42
	
147 42
	public static function parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix = '', $httpMethods = NULL) {
148 17
		if (! isset ( $routeArray ['path'] )) {
149
			$routeArray ['path'] = self::getPathFromMethod ( $method );
150 42
		}
151 42
		$pathParameters = self::addParamsPath ( $routeArray ['path'], $method, $routeArray ['requirements'] );
152 42
		$name = $routeArray ['name'];
153 42
		if (! isset ( $name )) {
154 42
			$name = self::generateRouteName($controllerClass,$methodName);
155 42
		}
156 42
		$cache = $routeArray ['cache'];
157 42
		$duration = $routeArray ['duration'];
158 42
		$path = $pathParameters ['path'];
159 17
		$parameters = $pathParameters ['parameters'];
160 42
		$priority = $routeArray ['priority'];
161
		$callback = $routeArray ['callback'] ?? null;
162
		$isRoot=false;
163 42
		$path = self::cleanpath ( $prefix, $path ,$isRoot);
164 42
		if (isset ( $routeArray ['methods'] ) && \is_array ( $routeArray ['methods'] )) {
165 1
			self::createRouteMethod ( $result, $controllerClass, $path, $routeArray ['methods'], $methodName, $parameters, $name, $cache, $duration, $priority, $callback , $isRoot);
166
		} elseif (\is_array ( $httpMethods )) {
167 42
			self::createRouteMethod ( $result, $controllerClass, $path, $httpMethods, $methodName, $parameters, $name, $cache, $duration, $priority, $callback , $isRoot);
168 17
		} else {
169
			$v = [ 'controller' => $controllerClass,'action' => $methodName,'parameters' => $parameters,'name' => $name,'cache' => $cache,'duration' => $duration,'priority' => $priority];
170 42
			if (isset ( $callback )) {
171
				$v ['callback'] = $callback;
172 42
			}
173
			if(!$isRoot && isset(self::$mainParams) && \count(self::$mainParams)>0){
174 17
				$v['main.params']=self::$mainParams;
175 17
			}
176 17
			$result [$path] = $v;
177 17
		}
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
			$httpMethod=\strtolower($httpMethod);
183
			if(\array_search($httpMethod, self::HTTP_METHODS)===false){
184 17
				throw new RouterException("$httpMethod is not a valid HTTP method!");
185
			}
186
			$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 17
			}
190
			if(!$isRoot && isset(self::$mainParams) && \count(self::$mainParams)>0){
191 17
				$v['main.params']=self::$mainParams;
192 17
			}
193
			$result [$path] [$httpMethod] = $v;
194
		}
195
	}
196
	
197
	public function isRest(): bool {
198 17
		return $this->rest;
199 17
	}
200 17
	
201
	/**
202
	 * @param bool $silent
203
	 */
204
	public function setSilent(bool $silent): void {
205
		$this->silent = $silent;
206
	}
207
}
208