GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

RwDispatcher   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 20

Test Coverage

Coverage 81.73%

Importance

Changes 0
Metric Value
dl 0
loc 230
ccs 85
cts 104
cp 0.8173
rs 9.0399
c 0
b 0
f 0
wmc 42
lcom 1
cbo 20

9 Methods

Rating   Name   Duplication   Size   Complexity  
B getCurrentMap() 0 35 7
A getCurrentModuleMap() 0 8 2
A getCurrentProcessorMap() 0 7 2
B getCurrentControllerMap() 0 26 6
A getFrontController() 0 22 5
C getProcessController() 0 58 14
A loadSiteMap() 0 15 3
A getView() 0 1 1
A getTemplatePath() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like RwDispatcher 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 RwDispatcher, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Parses the current request into a valid Front Controller / Controller pair
4
 * @package presentation
5
 * @subpackage dispatchers
6
 * @author marius orcsik <[email protected]>
7
 * @date 09.09.24
8
 */
9
namespace vsc\application\dispatchers;
10
11
use vsc\application\controllers\FrontControllerA;
12
use vsc\application\controllers\Html5Controller;
13
use vsc\application\processors\ErrorProcessor;
14
use vsc\application\processors\NotFoundProcessor;
15
use vsc\application\processors\ProcessorA;
16
use vsc\application\processors\StaticFileProcessor;
17
use vsc\application\sitemaps\ClassMap;
18
use vsc\application\sitemaps\ErrorControllerMap;
19
use vsc\application\sitemaps\ErrorProcessorMap;
20
use vsc\application\sitemaps\ExceptionSitemap;
21
use vsc\application\sitemaps\MappingA;
22
use vsc\application\sitemaps\ModuleMap;
23
use vsc\application\sitemaps\RootMap;
24
use vsc\infrastructure\vsc;
25
use vsc\presentation\requests\RwHttpRequest;
26
use vsc\presentation\responses\ExceptionResponseError;
27
use vsc\presentation\responses\ExceptionResponseRedirect;
28
use vsc\ExceptionError;
29
use vsc\presentation\responses\HttpResponseType;
30
31
class RwDispatcher extends HttpDispatcherA {
32
	/**
33
	 * @param array $aMaps
34
	 * @throws ExceptionError
35
	 * @returns ClassMap
36
	 */
37 20
	static protected function getCurrentMap($aMaps, $sUri = null) {
38 20
		if (!is_array($aMaps) || empty($aMaps)) {
39 1
			return new ErrorProcessorMap();
40
		}
41
42 19
		if (is_null($sUri)) {
43 19
			$sUri = vsc::getEnv()->getHttpRequest()->getUri(true);
44
		}
45 19
		$aRegexes = array_keys($aMaps);
46
47 19
		$aMatches = array();
48 19
		foreach ($aRegexes as $sRegex) {
49 19
			$sFullRegex = '#' . str_replace('#', '\#', $sRegex) . '#iu'; // i for insensitive, u for utf8
50
			try {
51 19
				$iMatch = preg_match_all($sFullRegex, $sUri, $aMatches, PREG_SET_ORDER);
52 1
			} catch (ExceptionError $e) {
53 1
				$f = new ExceptionError(
54 1
					$e->getMessage() . '<br/> Offending regular expression: <span style="font-weight:normal">' . $sFullRegex . '</span>',
55 1
					$e->getCode());
56 1
				throw $f;
57
			}
58 18
			if ($iMatch) {
59 18
				$aMatches = array_shift($aMatches);
60 18
				$aMatches = array_slice($aMatches, 1);
61
62
				/* @var MappingA $oMapping */
63 18
				$oMapping = $aMaps[$sRegex];
64 18
				$oMapping->setTaintedVars($aMatches);
65 18
				$oMapping->setUrl($sUri);
66 18
				$oMapping->getModuleMap()->setUrl($sUri);
0 ignored issues
show
Documentation Bug introduced by
The method getModuleMap does not exist on object<vsc\application\sitemaps\MappingA>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
67 18
				return $oMapping;
68
			}
69
		}
70
		return null;
71
	}
72
73
	/**
74
	 * @returns ModuleMap
75
	 * @throws ExceptionSitemap
76
	 */
77 2
	public function getCurrentModuleMap() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
78 2
		$oProcessorMap = $this->getCurrentProcessorMap();
79 2
		if (ClassMap::isValid($oProcessorMap)) {
0 ignored issues
show
Bug introduced by
It seems like $oProcessorMap defined by $this->getCurrentProcessorMap() on line 78 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
80 2
			return $this->getCurrentProcessorMap()->getModuleMap();
0 ignored issues
show
Documentation Bug introduced by
The method getModuleMap does not exist on object<vsc\application\sitemaps\MappingA>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
81
		} else {
82
			return $this->getSiteMap()->getCurrentModuleMap();
83
		}
84
	}
85
86
	/**
87
	 * @returns ClassMap
88
	 * @throws ExceptionSitemap
89
	 * @throws ExceptionError
90
	 */
91 19
	public function getCurrentProcessorMap() {
92 19
		$oProcessorMap = self::getCurrentMap($this->getSiteMap()->getMaps());
0 ignored issues
show
Documentation introduced by
$this->getSiteMap()->getMaps() is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
93 19
		if (!ClassMap::isValid($oProcessorMap)) {
0 ignored issues
show
Bug introduced by
It seems like $oProcessorMap defined by self::getCurrentMap($thi...etSiteMap()->getMaps()) on line 92 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
94
			$oProcessorMap = new ErrorProcessorMap(NotFoundProcessor::class);
95
		}
96 19
		return $oProcessorMap;
97
	}
98
99
	/**
100
	 * @returns ClassMap
101
	 * @throws ExceptionError
102
	 */
103 10
	public function getCurrentControllerMap() {
104 10
 		$oProcessorMap = $this->getCurrentProcessorMap();
105
106 10
		$oCurrentMap = null;
107
		// check if the current processor has some set maps
108 10
		$aProcessorCtrlMaps = $oProcessorMap->getControllerMaps();
109 10
		if (count($aProcessorCtrlMaps) > 0) {
110
			$oCurrentMap = self::getCurrentMap($aProcessorCtrlMaps);
111
			if (ClassMap::isValid($oCurrentMap) && !ErrorControllerMap::isValid($oCurrentMap)) {
0 ignored issues
show
Bug introduced by
It seems like $oCurrentMap defined by self::getCurrentMap($aProcessorCtrlMaps) on line 110 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
112
				return $oCurrentMap;
113
			}
114
		}
115
116 10
		$oCurrentModule = $oProcessorMap->getModuleMap();
0 ignored issues
show
Documentation Bug introduced by
The method getModuleMap does not exist on object<vsc\application\sitemaps\MappingA>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
117
		// merging all controller maps found in the processor map's parent modules
118
		do {
119
			// check the current module for maps
120 10
			$aModuleCtrlMaps = $oCurrentModule->getControllerMaps();
121 10
			if (count($aModuleCtrlMaps) > 0) {
122 10
				$oCurrentMap = self::getCurrentMap($aModuleCtrlMaps);
123
			}
124 10
			$oCurrentModule = $oCurrentModule->getModuleMap();
125 10
		} while (!ClassMap::isValid($oCurrentMap));
0 ignored issues
show
Bug introduced by
It seems like $oCurrentMap can be null; however, isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
126
127 10
		return $oCurrentMap;
128
	}
129
130
	/**
131
	 * @throws \vsc\application\sitemaps\ExceptionSitemap
132
	 * @throws \vsc\presentation\responses\ExceptionResponseError
133
	 * @returns FrontControllerA
134
	 */
135 1
	public function getFrontController() {
136 1
		if (!FrontControllerA::isValid($this->oController)) {
137 1
			$oControllerMapping = $this->getCurrentControllerMap();
138
139 1
			if (ClassMap::isValid($oControllerMapping)) {
0 ignored issues
show
Bug introduced by
It seems like $oControllerMapping defined by $this->getCurrentControllerMap() on line 137 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
140 1
				$sControllerName = $oControllerMapping->getPath();
141
			}
142
143 1
			if (empty($sControllerName)) {
144
				throw new ExceptionResponseError('Could not find the correct front controller', HttpResponseType::NOT_FOUND);
145
			}
146
147
			/* @var $this->oController FrontControllerA */
148 1
			$this->oController = new $sControllerName();
149 1
			if (FrontControllerA::isValid($this->oController)) {
150
				// adding the map to the controller, allows it to add resources (styles,scripts) from inside it
151 1
				$this->oController->setMap($oControllerMapping);
152
			}
153
		}
154
155 1
		return $this->oController;
156
	}
157
158
	/**
159
	 * (non-PHPdoc)
160
	 * @see vsc/presentation/dispatchers/HttpDispatcherA::getProcessController()
161
	 * @throws ExceptionSitemap
162
	 * @throws ExceptionResponseError
163
	 * @returns ProcessorA
164
	 */
165 3
	public function getProcessController() {
166 3
		if (!ProcessorA::isValid($this->oProcessor)) {
167 3
			$oProcessorMap = $this->getCurrentProcessorMap();
168 3
			if (!ClassMap::isValid($oProcessorMap)) {
0 ignored issues
show
Bug introduced by
It seems like $oProcessorMap defined by $this->getCurrentProcessorMap() on line 167 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
169
				// this mainly means nothing was matched to our url, or no mappings exist, so we're falling back to 404
170
				$oProcessorMap = new ErrorProcessorMap(NotFoundProcessor::class, '.*');
0 ignored issues
show
Unused Code introduced by
The call to ErrorProcessorMap::__construct() has too many arguments starting with '.*'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
171
				$oProcessorMap->setTemplatePath(VSC_SRC_PATH . 'templates');
172
				$oProcessorMap->setTemplate('404.php');
173
			}
174
175 3
			$sPath = $oProcessorMap->getPath();
176
			try {
177 3
				if (ClassMap::isValidMap($sPath) || (stristr(basename($sPath), '.') === false && !is_file($sPath))) {
178
179
					try {
180 2
						if (class_exists($sPath)) {
181 2
							$this->oProcessor = new $sPath();
182
						} else {
183 2
							$this->oProcessor = new NotFoundProcessor();
184
						}
185
					} catch (\Exception $e) {
186 2
						$this->oProcessor = new ErrorProcessor($e);
187
					}
188 1
				} elseif ($this->getSiteMap()->isValidStaticPath($sPath)) {
189
					// static stuff
190 1
					$this->oProcessor = new StaticFileProcessor();
191 1
					$this->oProcessor->setFilePath($sPath);
192
				} /*else {
193
					$this->oProcessor = new NotFoundProcessor();
194
				}*/
195
196 3
				if (ProcessorA::isValid($this->oProcessor)) {
197 3
					if (!(ErrorProcessor::isValid($this->oProcessor) && MappingA::isValid($this->oProcessor->getMap()))) {
198
						// @TODO: this should be a MappingA->merge() when the processor already has a map
199 2
						$this->oProcessor->setMap($oProcessorMap);
200
					}
201
202
					// setting the variables defined in the processor into the tainted variables
203
					/** @var RwHttpRequest $oRawRequest */
204 3
					$oRawRequest = $this->getRequest();
205 3
					if (RwHttpRequest::isValid($oRawRequest)) {
206 3
						$oRawRequest->setTaintedVars($this->oProcessor->getLocalVars()); // FIXME!!!
207
					}
208
				} else {
209
					// broken URL
210 3
					throw new ExceptionResponseError('Broken URL', 400);
211
				}
212
			} catch (ExceptionResponseRedirect $e) {
213
				// get the response
214
				$oResponse = vsc::getEnv()->getHttpResponse();
215
				$oResponse->setLocation($e->getLocation());
216
				ob_end_flush();
217
				$oResponse->outputHeaders();
218
			}
219
		}
220
221 3
		return $this->oProcessor;
222
	}
223
224
	/**
225
	 *
226
	 * @param string $sIncPath
227
	 * @throws \Exception
228
	 * @throws ExceptionSitemap
229
	 * @return boolean
230
	 */
231 19
	public function loadSiteMap($sIncPath) {
232
		try {
233
			// hic sunt leones
234
			/** @var ModuleMap $oMap */
235 19
			$oMap = $this->getSiteMap()->map('\A/', $sIncPath);
236 19
			if (count($oMap->getControllerMaps()) == 0) {
237 19
				$oMap->map('\A.*\Z', Html5Controller::class);
238
			}
239
		} catch (ExceptionSitemap $e) {
240
			// there was a faulty controller in the sitemap
241
			// this will probably result in a incomplete parsed sitemap tree
242
			throw ($e);
243
		}
244 19
		return true;
245
	}
246
247
	public function getView() {}
248
249 1
	public function getTemplatePath() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
250 1
		$aMaps = $this->getSiteMap()->getMaps();
251 1
		$oProcessorMap = self::getCurrentMap($aMaps);
0 ignored issues
show
Documentation introduced by
$aMaps is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
252
253 1
		if (ClassMap::isValid($oProcessorMap)) {
0 ignored issues
show
Bug introduced by
It seems like $oProcessorMap defined by self::getCurrentMap($aMaps) on line 251 can be null; however, vsc\application\sitemaps\ClassMap::isValid() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
254 1
			$sPath = $oProcessorMap->getTemplatePath();
255
		} else {
256
			$sPath = $this->getCurrentControllerMap()->getTemplatePath();
257
		}
258 1
		return $sPath;
259
	}
260
}
261