12
12
use Gt \Routing \Path \DynamicPath ;
13
13
use Gt \WebEngine \View \BaseView ;
14
14
use Gt \WebEngine \View \HTMLView ;
15
+ use Gt \WebEngine \View \NullView ;
15
16
16
17
class DefaultRouter extends BaseRouter {
17
18
#[Any(name: "page-route " , accept: "text/html,application/xhtml+xml " )]
18
19
public function page (Request $ request ):void {
19
20
$ pathMatcher = new PathMatcher ("page " );
20
21
$ 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 ;
29
49
}
30
50
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 ;
34
67
}
35
68
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
+ };
40
79
41
80
$ 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 ) ;
47
86
48
87
$ matchingLogics = $ pathMatcher ->findForUriPath (
49
88
$ request ->getUri ()->getPath (),
@@ -60,12 +99,74 @@ public function page(Request $request):void {
60
99
"page " ,
61
100
"html "
62
101
);
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 );
66
121
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
+ );
67
137
foreach ($ matchingViews as $ path ) {
68
138
$ this ->addToViewAssembly ($ path );
69
139
}
70
140
}
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
+ }
71
172
}
0 commit comments