@@ -9,6 +9,7 @@ class Router
99 private static $ pathNotFound ;
1010 private static $ methodNotAllowed ;
1111 private static string $ defaultConstraint = '([\w\-]+) ' ;
12+ private static string $ currentPrefix = '' ;
1213
1314 /**
1415 * A quick static function to register a route in the router. Used by the shorthand methods as well.
@@ -20,8 +21,13 @@ class Router
2021 */
2122 public static function add (string $ route , callable |string $ action , string |array $ methods = 'GET ' )
2223 {
24+ // If a prefix exists, prepend it to the route
25+ if (!empty (self ::$ currentPrefix )) {
26+ $ route = self ::$ currentPrefix .$ route ;
27+ }
28+
2329 self ::$ routes [] = [
24- 'route ' => $ route ,
30+ 'route ' => self :: trimRoute ( $ route) ,
2531 'action ' => $ action ,
2632 'methods ' => $ methods
2733 ];
@@ -34,6 +40,7 @@ public static function add(string $route, callable|string $action, string|array
3440 *
3541 * @param string $route
3642 * @param callable $action
43+ * @return Router
3744 */
3845 public static function get (string $ route , callable $ action )
3946 {
@@ -45,6 +52,7 @@ public static function get(string $route, callable $action)
4552 *
4653 * @param string $route
4754 * @param callable $action
55+ * @return Router
4856 */
4957 public static function post (string $ route , callable $ action )
5058 {
@@ -65,6 +73,7 @@ public static function getAllRoutes()
6573 * Defines an action to be called when a path isn't found - i.e. a 404
6674 *
6775 * @param callable $action
76+ * @return void
6877 */
6978 public static function pathNotFound (callable $ action )
7079 {
@@ -75,6 +84,7 @@ public static function pathNotFound(callable $action)
7584 * Defines an action to be called with a method isn't allowed on a route - i.e. a 405
7685 *
7786 * @param callable $action
87+ * @return void
7888 */
7989 public static function methodNotAllowed (callable $ action )
8090 {
@@ -92,6 +102,28 @@ public static function setDefaultConstraint(string $constraint = '([\w\-]+)')
92102 self ::$ defaultConstraint = $ constraint ;
93103 }
94104
105+ private static function trimRoute (string $ route ): string
106+ {
107+ $ route = trim (trim ($ route ), '/ ' );
108+ return "/ $ route " ;
109+ }
110+
111+ /**
112+ * Accepts a callable that defines routes, and adds a prefix to them.
113+ *
114+ * @param string $prefix The prefix you want added to the routes.
115+ * @param callable $routes A function that defines routes.
116+ * @return void
117+ */
118+ public static function prefix (string $ prefix , callable $ routes )
119+ {
120+ self ::$ currentPrefix = $ prefix ;
121+
122+ $ routes ();
123+
124+ self ::$ currentPrefix = '' ;
125+ }
126+
95127 /**
96128 * Define a constraint for a route parameter. If only passing one parameter,
97129 * provide the parameter name as first argument and constraint as second. If
@@ -134,7 +166,10 @@ private static function tokenize(string $uri)
134166 $ pattern = '{ ' .$ match .'} ' ;
135167
136168 if (in_array ($ match , $ constraints )) {
137- $ uri = str_replace ($ pattern , '( ' .self ::$ constraints [$ match ].') ' , $ uri );
169+ // Do some voodoo to allow users to use parentheses in their constraints if they want
170+ $ constraint = '( ' .rtrim (ltrim (trim (self ::$ constraints [$ match ]), '( ' ), ') ' ).') ' ;
171+
172+ $ uri = str_replace ($ pattern , $ constraint , $ uri );
138173 } else {
139174 $ uri = str_replace ($ pattern , self ::$ defaultConstraint , $ uri );
140175 }
@@ -149,25 +184,22 @@ private static function tokenize(string $uri)
149184 *
150185 * @param string $basePath
151186 * @param boolean $multimatch
187+ * @return void
152188 */
153189 public static function run (string $ basePath = '' , bool $ multimatch = false )
154190 {
155- $ basePath = rtrim ($ basePath, ' / ' );
191+ $ basePath = self :: trimRoute ($ basePath );
156192 $ method = $ _SERVER ['REQUEST_METHOD ' ];
157193 $ uri = parse_url ($ _SERVER ['REQUEST_URI ' ])['path ' ];
158- $ path = urldecode (rtrim ($ uri , '/ ' ));
159-
160- // If the path is empty (no slash in URI) place one to satisfy the root route ('/')
161- if (empty ($ path )) {
162- $ path = '/ ' ;
163- }
194+ $ path = urldecode (self ::trimRoute ($ uri ));
164195
165196 $ pathMatchFound = false ;
166197 $ routeMatchFound = false ;
167198
168199 // Begin looking through routes
169200 foreach (self ::$ routes as $ route ) {
170- if ($ basePath != '' && $ basePath != '/ ' ) {
201+ // If the basePath isn't just "root"
202+ if ($ basePath != '/ ' ) {
171203 $ route ['route ' ] = $ basePath .$ route ['route ' ];
172204 }
173205
0 commit comments