Test Setup Failed
Push — master ( ed6936...faa06d )
by Berend
01:43 queued 11s
created

AccessRouter::clear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace miBadger\Router;
4
5
use miBadger\Http\ServerRequest;
6
use miBadger\Http\ServerResponse;
7
use miBadger\Http\ServerResponseException;
8
9
class AccessRouter
10
{
11
	private $routes; // $routes[method] = (route, pattern, callable, permission)
12
13
	private $basePath;
14
15
	private $user;
16
17
	public function __construct(PermissionCheckable $user = null, $basePath = '')
18
	{
19
		$this->user = $user;
20
		$this->routes = [];
21
		$this->basePath = $basePath;
22
	}
23
	/**
24
	 * Returns the base path.
25
	 *
26
	 * @return string the base path.
27
	 */
28
	public function getBasePath()
29
	{
30
		return $this->basePath;
31
	}
32
33
	/**
34
	 * Set the base path.
35
	 *
36
	 * @param string $basePath
37
	 * @return $this
38
	 */
39
	public function setBasePath($basePath)
40
	{
41
		$this->basePath = $basePath;
42
43
		return $this;
44
	}
45
46
	/**
47
	 * {@inheritdoc}
48
	 */
49
	public function getIterator()
50
	{
51
		return new \RecursiveArrayIterator($this->routes);
52
	}
53
54
	/**
55
	 * Returns the number of key-value mappings in the router map.
56
	 *
57
	 * @return int the number of key-value mappings in the router map.
58
	 */
59
	public function count()
60
	{
61
		$result = 0;
62
63
		foreach ($this->routes as $routes) {
64
			$result += count($routes);
65
		}
66
67
		return $result;
68
	}
69
70 View Code Duplication
	public function add(string $method, string $route, $permission, callable $callable)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
71
	{
72
		$entry = (object)[
73
			'route' => $route,
74
			'pattern' => $this->createPattern($route),
75
			'permission' => $permission,
76
			'callable' => $callable
77
		];
78
79
		if (!array_key_exists($method, $this->routes)) {
80
			$this->routes[$method] = [];
81
		}
82
83
		$this->routes[$method][] = $entry;
84
	}
85
86
	/**
87
	 * Creates a regex-enabled pattern from the route
88
	 *
89
	 * @param string $route
90
	 * @return string the pattern string.
91
	 */
92
	private function createPattern(string $route)
93
	{
94
		return '|^' . preg_replace('|\{[^\}]+\}|', '([^\/]+)', $route) . '$|';
95
	}
96
97
	/**
98
	 * Removes the mapping for the specified route from the router map if present.
99
	 *
100
	 * @param string $method
101
	 * @param string $route
102
	 * @return null
103
	 */
104
	public function remove(string $method, string $route, $permission)
105
	{
106
		if (!array_key_exists($method, $this->routes)) {
107
			return;
108
		}
109
110
		foreach ($this->routes[$method] as $key => $entry) {
111
			if ($entry->route == $route && $entry->permission == $permission) {
112
				unset($this->routes[$method][$key]);
113
			}
114
		}
115
116
		if (count($this->routes[$method]) == 0) {
117
			unset($this->routes[$method]);
118
		}
119
	}
120
121
	/**
122
	 * Removes all of the mappings from the router map.
123
	 *
124
	 * @return null
125
	 */
126
	public function clear()
127
	{
128
		$this->routes = [];
129
	}
130
131
132
	/**
133
	 * Returns the result of the given route's callable.
134
	 *
135
	 * @param string|null $method = new ServerRequest()->getMethod()
136
	 * @param string|null $route = new ServerRequest()->getUri()->getPath()
137
	 * @return mixed the result of the given route's callable.
138
	 * @throws ServerResponseException
139
	 */
140 View Code Duplication
	public function resolve($method = null, $route = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
	{
142
		$serverRequest = new ServerRequest();
143
144
		if ($method === null) {
145
			$method = $serverRequest->getMethod();
146
		}
147
148
		if ($route === null) {
149
			$route = $serverRequest->getUri()->getPath();
150
		}
151
152
		if ($this->basePath !== '' && strpos($route, $this->basePath, 0) === 0) {
153
			$route = substr($route, strlen($this->basePath));
154
		}
155
156
		return $this->callCallable($this->getCallable($method, $route));
157
	}
158
159
	/**
160
	 * Returns the result of the callable.
161
	 *
162
	 * @param array the callable and the route matches.
163
	 * @return mixed the result the callable.
164
	 */
165
	protected function callCallable($callable)
166
	{
167
		return call_user_func_array($callable[0], $callable[1]);
168
	}
169
170
	public function getMatchingRoutes($method, $route)
171
	{
172
		if (!array_key_exists($method, $this->routes)) {
173
			throw new ServerResponseException(new ServerResponse(404));
174
		}
175
176
		$matchedRoutes = [];
177
178 View Code Duplication
		foreach ($this->routes[$method] as $entry) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
			if (preg_match($entry->pattern, $route, $matches) > 0) {
180
				// At this point the route is matched
181
				array_shift($matches);
182
				$matchedRoutes[] = [$route, $entry, $matches];
183
			}
184
		}
185
186
		if (count($matchedRoutes) == 0) {
187
			throw new ServerResponseException(new ServerResponse(404));		
188
		}
189
190
		return $matchedRoutes;
191
	}
192
193
	protected function getCallable($method, $route)
194
	{
195
		// Check if permissions are alright
196
		$matchedRoutes = $this->getMatchingRoutes($method, $route);
197
198
		foreach ($matchedRoutes as $match) {
199
			$route = $match[0];
0 ignored issues
show
Unused Code introduced by
$route is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
200
			$entry = $match[1];
201
			$matches = $match[2];
202
203
			if ($entry->permission === null 
204
				|| ($entry->permission !== null && $this->user !== null && $this->user->hasPermission($entry->permission)))
205
			{
206
				return [$entry->callable, $matches];
207
			}
208
209
		}
210
211
		throw new ServerResponseException(new ServerResponse(403));
212
	}
213
214
	/**
215
	 * Returns the cleaned ({token} => %s) permission map for the router 
216
	 * (associative map from route to the set of permissions that have access to that route), 
217
	 * 		null if a route has wildcard permissions
218
	 */
219
	public function makeGETRoutePermissionsMap()
220
	{
221
		$outputMap = [];
222
223
		foreach ($this->routes["GET"] as $entry) {
224
225
			// Extract clean route by replacing every slug occurrence with %s
226
			$slugFreeRoute = preg_replace('/({.*?})/', '%s', $entry->route);
227
228
			if ($entry->permission === null) {
229
				$outputMap[$slugFreeRoute] = null;	
230
				continue;
231
			}
232
233
			if (!isset($outputMap[$slugFreeRoute])) {
234
				$outputMap[$slugFreeRoute] = [];
235
			}
236
237
			$outputMap[$slugFreeRoute][] = $entry->permission;
238
		}
239
240
		return $outputMap;
241
	}
242
}