Passed
Push — master ( f7ade8...7e9287 )
by Jean-Christophe
11:26
created

ControllerParserPathTrait   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 78.69%

Importance

Changes 2
Bugs 1 Features 1
Metric Value
wmc 53
eloc 122
c 2
b 1
f 1
dl 0
loc 176
ccs 96
cts 122
cp 0.7869
rs 6.96

8 Methods

Rating   Name   Duplication   Size   Complexity  
A checkParams() 0 4 4
B checkParamsTypesForRequirement() 0 21 7
A scanParam() 0 17 5
B addParamsPath() 0 31 8
A parseMethodPath() 0 13 6
A getPathFromMethod() 0 20 5
B cleanpath() 0 21 10
B parseMainPath() 0 30 8

How to fix   Complexity   

Complex Class

Complex classes like ControllerParserPathTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ControllerParserPathTrait, and based on these observations, apply Extract Interface, too.

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 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 57
	private static function checkParams(\ReflectionFunctionAbstract $method,$actualParams){
43 57
		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 57
	}
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 57
	public static function parseMethodPath(\ReflectionFunctionAbstract $method, $path) {
74 57
		if (! isset ( $path ) || $path === '')
75
			return;
76 57
			$parameters = $method->getParameters ();
77 57
			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 57
			return $path;
86
	}
87
	
88 57
	public static function cleanpath($prefix, $path = "", &$isRoot=false) {
89 57
		$path = \str_replace ( '//', '/', $path );
90 57
		if ($prefix !== '' && ! UString::startswith ( $prefix, '/' )) {
91
			$prefix = '/' . $prefix;
92
		}
93 57
		if (! UString::endswith ( $prefix, '/' )) {
94 57
			$prefix = $prefix . '/';
95
		}
96 57
		if ($path !== '' && UString::startswith ( $path, '/' )) {
97 33
			$path = \substr ( $path, 1 );
98
		}
99 57
		if(UString::startswith($path,'#/')){
100 17
			$path=\substr($path,1);
101 17
			$isRoot=true;
102
		}else {
103 57
			$path = $prefix . $path;
104
		}
105 57
		if (! UString::endswith ( $path, '/' ) && ! UString::endswith ( $path, '(.*?)' ) && ! UString::endswith ( $path, '(index/)?' )) {
106 57
			$path = $path . '/';
107
		}
108 57
		return \str_replace ( '//', '/', $path );
109
	}
110
	
111 57
	public static function addParamsPath($path, \ReflectionFunctionAbstract $method, $requirements) {
112 57
		$parameters = [ ];
113 57
		$hasOptional = false;
114 57
		\preg_match_all ( '@\{(\.\.\.|\~)?(.+?)\}@s', $path, $matches );
115 57
		self::checkParams($method,$matches[2]??[]);
116 57
		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 57
		if ($hasOptional) {
139 17
			$path .= '/(.*?)';
140
		}
141 57
		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 17
			foreach ( $matches [1] as $paramMatch ) {
169 17
				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 17
					if(\property_exists($controllerClass,$paramMatch)){
179 17
						$rProp=new \ReflectionProperty($controllerClass,$paramMatch);
180 17
						if($rProp->isPublic()){
181 17
							$path = \str_replace('{' . $paramMatch . '}', '(.+?)', $path);
182 17
							self::$mainParams[]=$paramMatch;
183
						}else{
184 17
							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