Passed
Push — master ( f5da16...2e3bf1 )
by Jean-Christophe
12:28
created

ControllerParserPathTrait::scanParam()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 17
ccs 15
cts 15
cp 1
rs 9.4888
c 0
b 0
f 0
cc 5
nc 8
nop 8
crap 5

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\cache\CacheManager;
6
use Ubiquity\utils\base\UString;
7
use Ubiquity\orm\parser\Reflexion;
8
use Ubiquity\exceptions\ParserException;
9
10
/**
11
 * Ubiquity\cache\parser$ControllerParserPathTrait
12
 * This class is part of Ubiquity
13
 *
14
 * @author jcheron <[email protected]>
15
 * @version 1.1.0
16
 *
17
 */
18
trait ControllerParserPathTrait {
19
	protected static $mainParams;
20 17
	protected static function getPathFromMethod(\ReflectionMethod $method) {
21 17
		$methodName = $method->getName ();
22 17
		if ($methodName === "index") {
23 17
			$pathParts = [ "(index/)?" ];
24
		} else {
25 17
			$pathParts = [ $methodName ];
26
		}
27 17
		$parameters = $method->getParameters ();
28 17
		foreach ( $parameters as $parameter ) {
29
			if ($parameter->isVariadic ()) {
30
				$pathParts [] = '{...' . $parameter->getName () . '}';
31
				return "/" . \implode ( "/", $pathParts );
32
			}
33
			if (! $parameter->isOptional ()) {
34
				$pathParts [] = '{' . $parameter->getName () . '}';
35
			} else {
36
				$pathParts [\count ( $pathParts ) - 1] .= '{~' . $parameter->getName () . '}';
37
			}
38
		}
39 17
		return "/" . \implode ( "/", $pathParts );
40
	}
41
	
42 55
	private static function checkParams(\ReflectionFunctionAbstract $method,$actualParams){
43 55
		foreach ( $method->getParameters () as $param ) {
44 17
			if(!$param->isOptional() && \array_search($param->name,$actualParams)===false){
45
				throw new ParserException(sprintf('The parameter %s is not present in the route path although it is mandatory.',$param->name));
46
			}
47
		}
48 55
	}
49
	
50 17
	private static function checkParamsTypesForRequirement(\ReflectionFunctionAbstract $method){
51 17
		$requirements=[];
52 17
		foreach ( $method->getParameters () as $param ) {
53 17
			if($param->hasType()){
54
				$type=$param->getType();
55
				if($type instanceof \ReflectionNamedType){
56
					switch ($type->getName()){
57
						case 'int':
58
							$requirements[$param->getName()]='\d+';
59
							break;
60
						case 'bool':
61
							$requirements[$param->getName()]='[0-1]{1}';
62
							break;
63
						case 'float':
64
							$requirements[$param->getName()]='[+-]?([0-9]*[.])?[0-9]+';
65
							break;
66
					}
67
				}
68
			}
69
		}
70 17
		return $requirements;
71
	}
72
	
73 55
	public static function parseMethodPath(\ReflectionFunctionAbstract $method, $path) {
74 55
		if (! isset ( $path ) || $path === '')
75
			return;
76 55
			$parameters = $method->getParameters ();
77 55
			foreach ( $parameters as $parameter ) {
78 17
				$name = $parameter->getName ();
79 17
				if ($parameter->isVariadic ()) {
80 17
					$path = \str_replace ( '{' . $name . '}', '{...' . $name . '}', $path );
81 17
				} elseif ($parameter->isOptional ()) {
82 17
					$path = \str_replace ( '{' . $name . '}', '{~' . $name . '}', $path );
83
				}
84
			}
85 55
			return $path;
86
	}
87
	
88 55
	public static function cleanpath($prefix, $path = "", &$isRoot=false) {
89 55
		$path = \str_replace ( '//', '/', $path );
90 55
		if ($prefix !== '' && ! UString::startswith ( $prefix, '/' )) {
91
			$prefix = '/' . $prefix;
92
		}
93 55
		if (! UString::endswith ( $prefix, '/' )) {
94 55
			$prefix = $prefix . '/';
95
		}
96 55
		if ($path !== '' && UString::startswith ( $path, '/' )) {
97 33
			$path = \substr ( $path, 1 );
98
		}
99 55
		if(UString::startswith($path,'#/')){
100
			$path=\substr($path,1);
101
			$isRoot=true;
102
		}else {
103 55
			$path = $prefix . $path;
104
		}
105 55
		if (! UString::endswith ( $path, '/' ) && ! UString::endswith ( $path, '(.*?)' ) && ! UString::endswith ( $path, '(index/)?' )) {
106 55
			$path = $path . '/';
107
		}
108 55
		return \str_replace ( '//', '/', $path );
109
	}
110
	
111 55
	public static function addParamsPath($path, \ReflectionFunctionAbstract $method, $requirements) {
112 55
		$parameters = [ ];
113 55
		$hasOptional = false;
114 55
		\preg_match_all ( '@\{(\.\.\.|\~)?(.+?)\}@s', $path, $matches );
115 55
		self::checkParams($method,$matches[2]??[]);
116 55
		if (isset ( $matches [2] ) && \count ( $matches [2] ) > 0) {
117 17
			$path = \preg_quote ( $path );
118 17
			$params = Reflexion::getMethodParameters ( $method );
119 17
			$typeRequirements=self::checkParamsTypesForRequirement($method);
120 17
			$index = 0;
121 17
			foreach ( $matches [2] as $paramMatch ) {
122 17
				$find = \array_search ( $paramMatch, $params );
123 17
				if ($find !== false) {
124 17
					unset($params[$find]);
125 17
					$requirement = '.+?';
126 17
					if (isset ( $requirements [$paramMatch] )) {
127
						$requirement = $requirements [$paramMatch];
128 17
					}elseif (isset($typeRequirements[$paramMatch])){
129
						$requirement = $typeRequirements [$paramMatch];
130
					}
131 17
					self::scanParam ( $parameters, $hasOptional, $matches, $index, $paramMatch, $find, $path, $requirement );
132
				} else {
133
					throw new ParserException ( "{$paramMatch} is not a parameter of the method " . $method->name );
134
				}
135 17
				$index ++;
136
			}
137
		}
138 55
		if ($hasOptional) {
139 17
			$path .= '/(.*?)';
140
		}
141 55
		return [ 'path' => $path,'parameters' => $parameters ];
142
	}
143
	
144 17
	public static function scanParam(&$parameters, &$hasOptional, $matches, $index, $paramMatch, $find, &$path, $requirement) {
145 17
		$toReplace = true;
146 17
		if (isset ( $matches [1] [$index] )) {
147 17
			if ($matches [1] [$index] === '...') {
148 17
				$parameters [] = '*';
149 17
				$path = \str_replace ( '\{\.\.\.' . $paramMatch . '\}', '(.*?)', $path );
150 17
				$toReplace = false;
151 17
			} elseif ($matches [1] [$index] === '~') {
152 17
				$parameters [] = '~' . $find;
153 17
				$path = \str_replace ( '\{~' . $paramMatch . '\}', '', $path );
154 17
				$hasOptional = true;
155 17
				$toReplace = false;
156
			}
157
		}
158 17
		if ($toReplace) {
159 17
			$parameters [] = $find;
160 17
			$path = \str_replace ( '\{' . $paramMatch . '\}', "({$requirement})", $path );
161
		}
162 17
	}
163
	
164 17
	protected static function parseMainPath(string $path,string $controllerClass): string{
165 17
		\preg_match_all ( '@\{(.+?)\}@s', $path, $matches );
166 17
		self::$mainParams=[];
167 17
		if (isset ( $matches [1] ) && \count ( $matches [1] ) > 0) {
168
			foreach ( $matches [1] as $paramMatch ) {
169
				if(\substr($paramMatch, -2) === '()'){
170
					$method=\substr($paramMatch,0,\strlen($paramMatch)-2);
171
					if(\method_exists($controllerClass,$method)){
172
						self::$mainParams[]=$method;
173
						$path = \str_replace('{' . $paramMatch . '}', '(.+?)', $path);
174
					}else{
175
						throw new ParserException("Method $method does not exist on $controllerClass");
176
					}
177
				}else{
178
					if(\property_exists($controllerClass,$paramMatch)){
179
						$rProp=new \ReflectionProperty($controllerClass,$paramMatch);
180
						if($rProp->isPublic()){
181
							$path = \str_replace('{' . $paramMatch . '}', '(.+?)', $path);
182
							self::$mainParams[]=$paramMatch;
183
						}else{
184
							throw new ParserException("Property $paramMatch must be public $controllerClass");
185
						}
186
					}else{
187
						throw new ParserException("Property $paramMatch does not exist on $controllerClass");
188
					}
189
				}
190
				
191
			}
192
		}
193 17
		return $path;
194
	}
195
}
196
197