@@ -92,6 +92,11 @@ class Router
9292 */
9393 protected static $ groupRoute = '' ;
9494
95+ /**
96+ * Current group name prefix for named routes (e.g. "admin.")
97+ */
98+ protected static $ groupName = '' ;
99+
95100 /**
96101 * Default controller namespace
97102 */
@@ -158,6 +163,7 @@ public static function mount(string $path, $handler)
158163
159164 $ initialNamespace = static ::$ namespace ;
160165 $ initialGroupRoute = static ::$ groupRoute ;
166+ $ initialGroupName = static ::$ groupName ;
161167 $ initialLingoOptions = static ::$ lingoOptions ;
162168 $ initialSitemapOptions = static ::$ sitemapOptions ;
163169 $ initialGroupMiddleware = static ::$ routeGroupMiddleware ;
@@ -172,6 +178,12 @@ public static function mount(string $path, $handler)
172178 static ::$ routeGroupMiddleware = $ groupOptions ['middleware ' ];
173179 }
174180
181+ if (!empty ($ groupOptions ['name ' ])) {
182+ // group names cascade: group "admin" + route "users.index"
183+ // registers as "admin.users.index" — nested groups compose
184+ static ::$ groupName .= trim ($ groupOptions ['name ' ], '. ' ) . '. ' ;
185+ }
186+
175187 if (isset ($ groupOptions ['lingo.routes ' ])) {
176188 static ::$ lingoOptions ['lingo.routes ' ] = $ groupOptions ['lingo.routes ' ];
177189 }
@@ -184,6 +196,7 @@ public static function mount(string $path, $handler)
184196
185197 static ::$ namespace = $ initialNamespace ;
186198 static ::$ groupRoute = $ initialGroupRoute ;
199+ static ::$ groupName = $ initialGroupName ;
187200 static ::$ lingoOptions = $ initialLingoOptions ;
188201 static ::$ sitemapOptions = $ initialSitemapOptions ;
189202 static ::$ routeGroupMiddleware = $ initialGroupMiddleware ;
@@ -219,6 +232,10 @@ public static function match(string $allowedMethods, string $pattern, $handler)
219232
220233 list ($ handler , $ routeOptions ) = static ::mapHandler ($ handler );
221234
235+ if (!empty ($ routeOptions ['name ' ]) && static ::$ groupName !== '' ) {
236+ $ routeOptions ['name ' ] = static ::$ groupName . $ routeOptions ['name ' ];
237+ }
238+
222239 if (is_string ($ handler )) {
223240 $ namespace = static ::$ namespace ;
224241
@@ -443,6 +460,21 @@ public static function inertia(string $pattern, string $view, $data = [])
443460 * @param string $pattern The base route to use eg: /post
444461 * @param array|string $controller to handle route eg: PostController
445462 */
463+ /**
464+ * Derive the dot-name base for a resource: '/admin/users' -> 'admin.users',
465+ * '/' inside a group -> the group's last segment
466+ */
467+ protected static function resourceName (string $ pattern ): string
468+ {
469+ $ base = trim ($ pattern , '/ ' );
470+
471+ if ($ base === '' ) {
472+ $ base = trim (basename (static ::$ groupRoute ), '/ ' );
473+ }
474+
475+ return str_replace ('/ ' , '. ' , $ base );
476+ }
477+
446478 public static function resource (string $ pattern , $ controller )
447479 {
448480 if (is_array ($ controller )) {
@@ -455,13 +487,15 @@ public static function resource(string $pattern, $controller)
455487 return static ::group ($ pattern , $ controller );
456488 }
457489
458- static ::match ('GET|HEAD ' , $ pattern , "$ controller@index " );
459- static ::post ($ pattern , "$ controller@store " );
460- static ::match ('GET|HEAD ' , "$ pattern/create " , "$ controller@create " );
461- static ::match ('DELETE ' , "$ pattern/{id} " , "$ controller@destroy " );
462- static ::match ('PUT|PATCH ' , "$ pattern/{id} " , "$ controller@update " );
463- static ::match ('GET|HEAD ' , "$ pattern/{id}/edit " , "$ controller@edit " );
464- static ::match ('GET|HEAD ' , "$ pattern/{id} " , "$ controller@show " );
490+ $ name = static ::resourceName ($ pattern );
491+
492+ static ::match ('GET|HEAD ' , $ pattern , ['name ' => "$ name.index " , "$ controller@index " ]);
493+ static ::post ($ pattern , ['name ' => "$ name.store " , "$ controller@store " ]);
494+ static ::match ('GET|HEAD ' , "$ pattern/create " , ['name ' => "$ name.create " , "$ controller@create " ]);
495+ static ::match ('DELETE ' , "$ pattern/{id} " , ['name ' => "$ name.destroy " , "$ controller@destroy " ]);
496+ static ::match ('PUT|PATCH ' , "$ pattern/{id} " , ['name ' => "$ name.update " , "$ controller@update " ]);
497+ static ::match ('GET|HEAD ' , "$ pattern/{id}/edit " , ['name ' => "$ name.edit " , "$ controller@edit " ]);
498+ static ::match ('GET|HEAD ' , "$ pattern/{id} " , ['name ' => "$ name.show " , "$ controller@show " ]);
465499
466500 // still keeping DELETE and PUT|PATCH so earlier versions of leaf apps don't break
467501 static ::match ('POST|DELETE ' , "$ pattern/{id}/delete " , "$ controller@destroy " );
@@ -494,11 +528,13 @@ public static function apiResource(string $pattern, $controller)
494528 return static ::group ($ pattern , $ controller );
495529 }
496530
497- static ::match ('GET|HEAD ' , $ pattern , "$ controller@index " );
498- static ::post ($ pattern , "$ controller@store " );
499- static ::match ('GET|HEAD ' , "$ pattern/{id} " , "$ controller@show " );
500- static ::match ('DELETE ' , "$ pattern/{id} " , "$ controller@destroy " );
501- static ::match ('PUT|PATCH ' , "$ pattern/{id} " , "$ controller@update " );
531+ $ name = static ::resourceName ($ pattern );
532+
533+ static ::match ('GET|HEAD ' , $ pattern , ['name ' => "$ name.index " , "$ controller@index " ]);
534+ static ::post ($ pattern , ['name ' => "$ name.store " , "$ controller@store " ]);
535+ static ::match ('GET|HEAD ' , "$ pattern/{id} " , ['name ' => "$ name.show " , "$ controller@show " ]);
536+ static ::match ('DELETE ' , "$ pattern/{id} " , ['name ' => "$ name.destroy " , "$ controller@destroy " ]);
537+ static ::match ('PUT|PATCH ' , "$ pattern/{id} " , ['name ' => "$ name.update " , "$ controller@update " ]);
502538
503539 // still keeping DELETE and PUT|PATCH so earlier versions of leaf apps don't break
504540 static ::match ('POST|DELETE ' , "$ pattern/{id}/delete " , "$ controller@destroy " );
@@ -1110,6 +1146,7 @@ public static function reset(): void
11101146 ];
11111147 static ::$ sitemapOptions = [];
11121148 static ::$ groupRoute = '' ;
1149+ static ::$ groupName = '' ;
11131150 static ::$ namespace = '' ;
11141151 static ::$ serverBasePath = null ;
11151152 static ::$ currentUri = null ;
0 commit comments