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