Skip to content

Commit 1ab3182

Browse files
author
Greg Bowler
authored
feature: improve default routing, closes phpgt/Routing#61 (#648)
1 parent 7467e81 commit 1ab3182

File tree

1 file changed

+124
-23
lines changed

1 file changed

+124
-23
lines changed

router.default.php

+124-23
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,77 @@
1212
use Gt\Routing\Path\DynamicPath;
1313
use Gt\WebEngine\View\BaseView;
1414
use Gt\WebEngine\View\HTMLView;
15+
use Gt\WebEngine\View\NullView;
1516

1617
class DefaultRouter extends BaseRouter {
1718
#[Any(name: "page-route", accept: "text/html,application/xhtml+xml")]
1819
public function page(Request $request):void {
1920
$pathMatcher = new PathMatcher("page");
2021
$this->setViewClass(HTMLView::class);
21-
$pathMatcher->addFilter(function(string $filePath, string $uriPath, string $baseDir):bool {
22-
// There are three types of matching files: Basic, Magic and Dynamic.
23-
// Basic is where a URI matches directly to a file on disk.
24-
// Magic is where a URI matches a PHP.Gt-specific file, like _common or _header.
25-
// Dynamic is where a URI matches a file/directory marked as dynamic with "@".
26-
$basicFileMatch = new BasicFileMatch($filePath, $baseDir);
27-
if($basicFileMatch->matches($uriPath)) {
28-
return true;
22+
$this->pathMatcherFilter($pathMatcher);
23+
24+
// This sort function allow multiple headers and footers to be in nested
25+
// directories, so the highest level header is at the start of the list,
26+
// with the reverse logic applied to footers.
27+
// TODO: Extract into own function. Should this be maintained within PHP.Gt/Routing ?
28+
$headerFooterSort = function(string $a, string $b):int {
29+
$fileNameA = pathinfo($a, PATHINFO_FILENAME);
30+
$fileNameB = pathinfo($b, PATHINFO_FILENAME);
31+
32+
if($fileNameA === "_header") {
33+
if($fileNameB === "_header") {
34+
$aDepth = substr_count($a, "/");
35+
$bDepth = substr_count($b, "/");
36+
if($aDepth > $bDepth) {
37+
return 1;
38+
}
39+
elseif($aDepth < $bDepth) {
40+
return -1;
41+
}
42+
else {
43+
return 0;
44+
}
45+
}
46+
47+
48+
return -1;
2949
}
3050

31-
$magicFileMatch = new MagicFileMatch($filePath, $baseDir);
32-
if($magicFileMatch->matches($uriPath)) {
33-
return true;
51+
if($fileNameA === "_footer") {
52+
if($fileNameB === "_footer") {
53+
$aDepth = substr_count($a, "/");
54+
$bDepth = substr_count($b, "/");
55+
if($aDepth < $bDepth) {
56+
return 1;
57+
}
58+
elseif($aDepth > $bDepth) {
59+
return -1;
60+
}
61+
else {
62+
return 0;
63+
}
64+
}
65+
66+
return 1;
3467
}
3568

36-
return false;
37-
});
38-
// TODO: add logic and view assembly in the api directory
39-
// (configured from $this->routerConfig)
69+
if($fileNameB === "_header") {
70+
return 1;
71+
}
72+
73+
if($fileNameB === "_footer") {
74+
return -1;
75+
}
76+
77+
return 0;
78+
};
4079

4180
$sortNestLevelCallback = fn(string $a, string $b) =>
42-
substr_count($a, "/") > substr_count($b, "/");
43-
$headerSort = fn(string $a, string $b) =>
44-
strtok(basename($a), ".") === "_header" ? -1 : 1;
45-
$footerSort = fn(string $a, string $b) =>
46-
strtok(basename($a), ".") === "_footer" ? 1 : -1;
81+
substr_count($a, "/") > substr_count($b, "/")
82+
? 1
83+
: (substr_count($a, "/") < substr_count($b, "/")
84+
? -1
85+
: 0);
4786

4887
$matchingLogics = $pathMatcher->findForUriPath(
4988
$request->getUri()->getPath(),
@@ -60,12 +99,74 @@ public function page(Request $request):void {
6099
"page",
61100
"html"
62101
);
63-
usort($matchingViews, $sortNestLevelCallback);
64-
usort($matchingViews, $headerSort);
65-
usort($matchingViews, $footerSort);
102+
usort($matchingViews, $headerFooterSort);
103+
foreach($matchingViews as $path) {
104+
$this->addToViewAssembly($path);
105+
}
106+
}
107+
108+
#[Any(name: "api-route", accept: "application/xml,application/json")]
109+
public function api(
110+
Request $request
111+
):void {
112+
$pathMatcher = new PathMatcher("api");
113+
$this->pathMatcherFilter($pathMatcher);
114+
$this->setViewClass(NullView::class);
115+
$sortNestLevelCallback = fn(string $a, string $b) =>
116+
substr_count($a, "/") > substr_count($b, "/")
117+
? 1
118+
: (substr_count($a, "/") < substr_count($b, "/")
119+
? -1
120+
: 0);
66121

122+
$matchingLogics = $pathMatcher->findForUriPath(
123+
$request->getUri()->getPath(),
124+
"api",
125+
"php"
126+
);
127+
usort($matchingLogics, $sortNestLevelCallback);
128+
foreach($matchingLogics as $path) {
129+
$this->addToLogicAssembly($path);
130+
}
131+
132+
$matchingViews = $pathMatcher->findForUriPath(
133+
$request->getUri()->getPath(),
134+
"api",
135+
"xml"
136+
);
67137
foreach($matchingViews as $path) {
68138
$this->addToViewAssembly($path);
69139
}
70140
}
141+
142+
public function pathMatcherFilter(PathMatcher $pathMatcher):void {
143+
$pathMatcher->addFilter(function(string $filePath, string $uriPath, string $baseDir):bool {
144+
foreach(glob($baseDir . $uriPath . ".*") as $globMatch) {
145+
$URI_CONTAINER = pathinfo($uriPath, PATHINFO_DIRNAME);
146+
$TRIM_THIS = $baseDir . $URI_CONTAINER;
147+
if(str_starts_with($globMatch, $TRIM_THIS)) {
148+
$trimmed = substr($filePath, strlen($TRIM_THIS));
149+
if(str_contains($trimmed, "@")) {
150+
return false;
151+
}
152+
}
153+
}
154+
155+
// There are three types of matching files: Basic, Magic and Dynamic.
156+
// Basic is where a URI matches directly to a file on disk.
157+
// Magic is where a URI matches a PHP.Gt-specific file, like _common or _header.
158+
// Dynamic is where a URI matches a file/directory marked as dynamic with "@".
159+
$basicFileMatch = new BasicFileMatch($filePath, $baseDir);
160+
if($basicFileMatch->matches($uriPath)) {
161+
return true;
162+
}
163+
164+
$magicFileMatch = new MagicFileMatch($filePath, $baseDir);
165+
if($magicFileMatch->matches($uriPath)) {
166+
return true;
167+
}
168+
169+
return false;
170+
});
171+
}
71172
}

0 commit comments

Comments
 (0)