Skip to content

Commit 903d00a

Browse files
authored
Merge pull request #42 from PhpSlides/dev
Dev
2 parents 9cec2fe + 9638f7d commit 903d00a

File tree

13 files changed

+813
-564
lines changed

13 files changed

+813
-564
lines changed

Router/MapRoute.php

+182-39
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,53 @@
66
use PhpSlides\Foundation\Application;
77
use PhpSlides\Interface\MapInterface;
88

9+
910
/**
10-
* Map Configuration
11+
* Class MapRoute
12+
*
13+
* This class is responsible for mapping and matching routes against the current request URI and HTTP method.
14+
* It extends the Controller class and implements the MapInterface interface.
15+
*
16+
* @author dconco <info@dconco.dev>
17+
* @version 1.4.0
18+
* @package PhpSlides
1119
*/
1220
class MapRoute extends Controller implements MapInterface
1321
{
22+
/**
23+
* @var string|array $route The route(s) to be mapped.
24+
*/
1425
private static string|array $route;
26+
27+
/**
28+
* @var string $request_uri The URI of the current request.
29+
*/
1530
private static string $request_uri;
31+
32+
/**
33+
* @var array $method An array to store HTTP methods for routing.
34+
*/
1635
private static array $method;
1736

37+
1838
/**
19-
* Validating $route methods
39+
* Matches the given HTTP method and route against the current request URI.
40+
*
41+
* @param string $method The HTTP method(s) to match, separated by '|'.
42+
* @param string|array $route The route pattern(s) to match.
43+
* @return bool|array Returns false if no match is found, or an array with the matched method, route, and parameters if a match is found.
2044
*
21-
* @param int $method
22-
* @param string|array $route
45+
* The function performs the following steps:
46+
* - Sets the HTTP method(s) to match.
47+
* - Normalizes the request URI by removing leading and trailing slashes and converting to lowercase.
48+
* - Normalizes the route pattern(s) by removing leading and trailing slashes and converting to lowercase.
49+
* - Checks if the route contains a pattern and resolves it if necessary.
50+
* - Extracts parameter names from the route pattern.
51+
* - Matches the request URI against the route pattern and extracts parameter values.
52+
* - Constructs a regex pattern to match the route.
53+
* - Checks if the request method is allowed for the matched route.
54+
* - Returns an array with the matched method, route, and parameters if a match is found.
55+
* - Returns false if no match is found.
2356
*/
2457
public function match(string $method, string|array $route): bool|array
2558
{
@@ -31,13 +64,34 @@ public function match(string $method, string|array $route): bool|array
3164
* ----------------------------------------------
3265
*/
3366
self::$request_uri = strtolower(
34-
preg_replace("/(^\/)|(\/$)/", '', Application::$request_uri),
67+
preg_replace("/(^\/)|(\/$)/", '', Application::$request_uri),
3568
);
3669
self::$request_uri = empty(self::$request_uri) ? '/' : self::$request_uri;
3770

3871
self::$route = is_array($route)
39-
? $route
40-
: strtolower(preg_replace("/(^\/)|(\/$)/", '', $route));
72+
? $route
73+
: strtolower(preg_replace("/(^\/)|(\/$)/", '', $route));
74+
75+
// Firstly, resolve route with pattern
76+
if (is_array(self::$route))
77+
{
78+
foreach (self::$route as $value)
79+
{
80+
if (str_starts_with('pattern:', $value))
81+
{
82+
$pattern = true;
83+
}
84+
}
85+
86+
if ($pattern === true)
87+
{
88+
return $this->pattern();
89+
}
90+
}
91+
else if (str_starts_with('pattern:', self::$route))
92+
{
93+
return $this->pattern();
94+
}
4195

4296
// will store all the parameters value in this array
4397
$req = [];
@@ -47,12 +101,14 @@ public function match(string $method, string|array $route): bool|array
47101
$paramKey = [];
48102

49103
// finding if there is any {?} parameter in $route
50-
if (is_string(self::$route)) {
104+
if (is_string(self::$route))
105+
{
51106
preg_match_all('/(?<={).+?(?=})/', self::$route, $paramMatches);
52107
}
53108

54109
// if the route does not contain any param call routing();
55-
if (empty($paramMatches[0] ?? []) || is_array(self::$route)) {
110+
if (empty($paramMatches) || is_array(self::$route))
111+
{
56112
/**
57113
* ------------------------------------------------------
58114
* | Check if $callback is a callable function
@@ -64,7 +120,8 @@ public function match(string $method, string|array $route): bool|array
64120
}
65121

66122
// setting parameters names
67-
foreach ($paramMatches[0] as $key) {
123+
foreach ($paramMatches[0] as $key)
124+
{
68125
$paramKey[] = $key;
69126
}
70127

@@ -75,8 +132,10 @@ public function match(string $method, string|array $route): bool|array
75132
$indexNum = [];
76133

77134
// storing index number, where {?} parameter is required with the help of regex
78-
foreach ($uri as $index => $param) {
79-
if (preg_match('/{.*}/', $param)) {
135+
foreach ($uri as $index => $param)
136+
{
137+
if (preg_match('/{.*}/', $param))
138+
{
80139
$indexNum[] = $index;
81140
}
82141
}
@@ -93,14 +152,16 @@ public function match(string $method, string|array $route): bool|array
93152
* | Running for each loop to set the exact index number with reg expression this will help in matching route
94153
* ----------------------------------------------------------------------------------
95154
*/
96-
foreach ($indexNum as $key => $index) {
155+
foreach ($indexNum as $key => $index)
156+
{
97157
/**
98158
* --------------------------------------------------------------------------------
99159
* | In case if req uri with param index is empty then return because URL is not valid for this route
100160
* --------------------------------------------------------------------------------
101161
*/
102162

103-
if (empty($reqUri[$index])) {
163+
if (empty($reqUri[$index]))
164+
{
104165
return false;
105166
}
106167

@@ -124,64 +185,146 @@ public function match(string $method, string|array $route): bool|array
124185
$reqUri = str_replace('/', '\\/', $reqUri);
125186

126187
// now matching route with regex
127-
if (preg_match("/$reqUri/", self::$route)) {
188+
if (preg_match("/$reqUri/", self::$route))
189+
{
128190
// checks if the requested method is of the given route
129191
if (
130-
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
131-
!in_array('optional', self::$method)
132-
) {
192+
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
193+
!in_array('*', self::$method)
194+
)
195+
{
133196
http_response_code(405);
134197
exit('Method Not Allowed');
135198
}
136199

137200
return [
138-
'method' => $_SERVER['REQUEST_METHOD'],
139-
'route' => self::$route,
140-
'params_value' => $req_value,
141-
'params' => $req,
201+
'method' => $_SERVER['REQUEST_METHOD'],
202+
'route' => self::$route,
203+
'params_value' => $req_value,
204+
'params' => $req,
142205
];
143206
}
144207

145208
return false;
146209
}
147210

148-
private function match_routing(): bool|array
211+
212+
/**
213+
* Matches the current request URI and method against the defined routes.
214+
*
215+
* This method checks if the current request URI matches any of the defined routes
216+
* and if the request method is allowed for the matched route. If a match is found,
217+
* it returns an array containing the request method and the matched route. If no
218+
* match is found, it returns false.
219+
*
220+
* @return bool|array Returns an array with 'method' and 'route' keys if a match is found, otherwise false.
221+
*/
222+
private function match_routing (): bool|array
149223
{
150224
$uri = [];
151225
$str_route = '';
152226

153-
if (is_array(self::$route)) {
154-
for ($i = 0; $i < count(self::$route); $i++) {
227+
if (is_array(self::$route))
228+
{
229+
for ($i = 0; $i < count(self::$route); $i++)
230+
{
155231
$each_route = preg_replace("/(^\/)|(\/$)/", '', self::$route[$i]);
156232

157233
empty($each_route)
158-
? array_push($uri, strtolower('/'))
159-
: array_push($uri, strtolower($each_route));
234+
? array_push($uri, strtolower('/'))
235+
: array_push($uri, strtolower($each_route));
160236
}
161-
} else {
237+
}
238+
else
239+
{
162240
$str_route = empty(self::$route) ? '/' : self::$route;
163241
}
164242

165243
if (
166-
in_array(self::$request_uri, $uri) ||
167-
self::$request_uri === $str_route
168-
) {
244+
in_array(self::$request_uri, $uri) ||
245+
self::$request_uri === $str_route
246+
)
247+
{
169248
if (
170-
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
171-
!in_array('optional', self::$method)
172-
) {
249+
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
250+
!in_array('*', haystack: self::$method)
251+
)
252+
{
173253
http_response_code(405);
174254
exit('Method Not Allowed');
175255
}
176256

177-
$method = implode('|', self::$method);
178-
179257
return [
180-
'method' => $_SERVER['REQUEST_METHOD'],
181-
'route' => self::$route,
258+
'method' => $_SERVER['REQUEST_METHOD'],
259+
'route' => self::$route,
182260
];
183-
} else {
261+
}
262+
else
263+
{
184264
return false;
185265
}
186266
}
267+
268+
269+
/**
270+
* Validates and matches a route pattern.
271+
*
272+
* This method checks if the route is an array and iterates through each value to find a pattern match.
273+
* If a pattern match is found, it validates the pattern and returns the matched result.
274+
* If no match is found in the array, it returns false.
275+
* If the route is not an array, it directly validates the pattern and returns the result.
276+
*
277+
* @return array|bool The matched pattern as an array if found, or false if no match is found.
278+
*/
279+
private function pattern (): array|bool
280+
{
281+
if (is_array(self::$route))
282+
{
283+
foreach (self::$route as $value)
284+
{
285+
if (str_starts_with('pattern:', $value))
286+
{
287+
$matched = $this->validatePattern($value);
288+
289+
if ($matched)
290+
{
291+
return $matched;
292+
}
293+
}
294+
}
295+
return false;
296+
}
297+
298+
return $this->validatePattern(self::$route);
299+
}
300+
301+
302+
/**
303+
* Validates the given pattern against the request URI and checks the request method.
304+
*
305+
* @param string $pattern The pattern to validate.
306+
* @return array|bool Returns an array with the request method and route if the pattern matches, otherwise false.
307+
*/
308+
private function validatePattern (string $pattern): array|bool
309+
{
310+
$pattern = trim(substr($pattern, 8));
311+
312+
if (fnmatch($pattern, self::$request_uri))
313+
{
314+
if (
315+
!in_array($_SERVER['REQUEST_METHOD'], self::$method) &&
316+
!in_array('*', self::$method)
317+
)
318+
{
319+
http_response_code(405);
320+
exit('Method Not Allowed');
321+
}
322+
323+
return [
324+
'method' => $_SERVER['REQUEST_METHOD'],
325+
'route' => self::$route,
326+
];
327+
}
328+
return false;
329+
}
187330
}

0 commit comments

Comments
 (0)