@@ -260,6 +260,79 @@ protected static function processMiddleware(Events\LifecycleEvent $event): void
260260 }
261261 }
262262
263+ /**
264+ * Register view namespaces collected by a lifecycle event.
265+ */
266+ protected static function processViews (Events \LifecycleEvent $ event ): void
267+ {
268+ foreach ($ event ->viewRequests () as [$ namespace , $ path ]) {
269+ if (is_dir ($ path )) {
270+ view ()->addNamespace ($ namespace , $ path );
271+ }
272+ }
273+ }
274+
275+ /**
276+ * Register Livewire components collected by a lifecycle event.
277+ */
278+ protected static function processLivewire (Events \LifecycleEvent $ event ): void
279+ {
280+ if (! class_exists (Livewire::class)) {
281+ return ;
282+ }
283+
284+ foreach ($ event ->livewireRequests () as [$ alias , $ class ]) {
285+ Livewire ::component ($ alias , $ class );
286+ }
287+ }
288+
289+ /**
290+ * Deduplicate route names and refresh router lookups.
291+ *
292+ * Called after every route-registering fire* method so that multi-domain
293+ * registrations of the same route file do not produce duplicate names,
294+ * and so that name/action lookups reflect the newly added routes.
295+ */
296+ protected static function refreshRoutes (): void
297+ {
298+ static ::deduplicateRouteNames ();
299+
300+ $ routes = app ('router ' )->getRoutes ();
301+ $ routes ->refreshNameLookups ();
302+ $ routes ->refreshActionLookups ();
303+ }
304+
305+ /**
306+ * Strip duplicate route names from the route collection.
307+ *
308+ * When the same route file is registered on multiple domains, each domain
309+ * gets identical route names (e.g. 'hub.dashboard' appears for core.test,
310+ * hub.core.test, core.localhost). Laravel's route:cache fails with
311+ * "Another route has already been assigned name" when duplicates exist.
312+ *
313+ * This keeps the name on the first registered route and strips it from
314+ * subsequent duplicates, allowing route:cache to succeed.
315+ */
316+ protected static function deduplicateRouteNames (): void
317+ {
318+ $ routes = app ('router ' )->getRoutes ();
319+ $ seen = [];
320+
321+ foreach ($ routes ->getRoutes () as $ route ) {
322+ $ name = $ route ->getName ();
323+
324+ if ($ name === null || $ name === '' ) {
325+ continue ;
326+ }
327+
328+ if (isset ($ seen [$ name ])) {
329+ unset($ route ->action ['as ' ]);
330+ } else {
331+ $ seen [$ name ] = true ;
332+ }
333+ }
334+ }
335+
263336 /**
264337 * Fire WebRoutesRegistering and process collected requests.
265338 *
@@ -280,29 +353,14 @@ public static function fireWebRoutes(): void
280353 event ($ event );
281354
282355 static ::processMiddleware ($ event );
356+ static ::processViews ($ event );
357+ static ::processLivewire ($ event );
283358
284- // Process view namespace requests
285- foreach ($ event ->viewRequests () as [$ namespace , $ path ]) {
286- if (is_dir ($ path )) {
287- view ()->addNamespace ($ namespace , $ path );
288- }
289- }
290-
291- // Process Livewire component requests
292- foreach ($ event ->livewireRequests () as [$ alias , $ class ]) {
293- if (class_exists (Livewire::class)) {
294- Livewire ::component ($ alias , $ class );
295- }
296- }
297-
298- // Process route requests
299359 foreach ($ event ->routeRequests () as $ callback ) {
300360 Route ::middleware ('web ' )->group ($ callback );
301361 }
302362
303- // Refresh route lookups after adding routes
304- app ('router ' )->getRoutes ()->refreshNameLookups ();
305- app ('router ' )->getRoutes ()->refreshActionLookups ();
363+ static ::refreshRoutes ();
306364 }
307365
308366 /**
@@ -327,38 +385,21 @@ public static function fireAdminBooting(): void
327385 event ($ event );
328386
329387 static ::processMiddleware ($ event );
388+ static ::processViews ($ event );
330389
331- // Process view namespace requests
332- foreach ($ event ->viewRequests () as [$ namespace , $ path ]) {
333- if (is_dir ($ path )) {
334- view ()->addNamespace ($ namespace , $ path );
335- }
336- }
337-
338- // Process translation requests
339390 foreach ($ event ->translationRequests () as [$ namespace , $ path ]) {
340391 if (is_dir ($ path )) {
341392 app ('translator ' )->addNamespace ($ namespace , $ path );
342393 }
343394 }
344395
345- // Process Livewire component requests
346- foreach ($ event ->livewireRequests () as [$ alias , $ class ]) {
347- if (class_exists (Livewire::class)) {
348- Livewire ::component ($ alias , $ class );
349- }
350- }
396+ static ::processLivewire ($ event );
351397
352- // Process route requests with admin middleware
353398 foreach ($ event ->routeRequests () as $ callback ) {
354399 Route ::middleware ('admin ' )->group ($ callback );
355400 }
356401
357- // Note: Navigation is handled via AdminMenuProvider interface.
358- // Modules implementing that interface will have their navigation
359- // registered through the existing AdminMenuRegistry::register() call.
360- // The $event->navigation() requests are available for future use
361- // when we move away from the AdminMenuProvider pattern.
402+ static ::refreshRoutes ();
362403 }
363404
364405 /**
@@ -377,29 +418,14 @@ public static function fireClientRoutes(): void
377418 event ($ event );
378419
379420 static ::processMiddleware ($ event );
421+ static ::processViews ($ event );
422+ static ::processLivewire ($ event );
380423
381- // Process view namespace requests
382- foreach ($ event ->viewRequests () as [$ namespace , $ path ]) {
383- if (is_dir ($ path )) {
384- view ()->addNamespace ($ namespace , $ path );
385- }
386- }
387-
388- // Process Livewire component requests
389- foreach ($ event ->livewireRequests () as [$ alias , $ class ]) {
390- if (class_exists (Livewire::class)) {
391- Livewire ::component ($ alias , $ class );
392- }
393- }
394-
395- // Process route requests with client middleware
396424 foreach ($ event ->routeRequests () as $ callback ) {
397425 Route ::middleware ('client ' )->group ($ callback );
398426 }
399427
400- // Refresh route lookups after adding routes
401- app ('router ' )->getRoutes ()->refreshNameLookups ();
402- app ('router ' )->getRoutes ()->refreshActionLookups ();
428+ static ::refreshRoutes ();
403429 }
404430
405431 /**
@@ -419,10 +445,11 @@ public static function fireApiRoutes(): void
419445
420446 static ::processMiddleware ($ event );
421447
422- // Process route requests with api middleware
423448 foreach ($ event ->routeRequests () as $ callback ) {
424449 Route ::middleware ('api ' )->group ($ callback );
425450 }
451+
452+ static ::refreshRoutes ();
426453 }
427454
428455 /**
@@ -442,10 +469,11 @@ public static function fireMcpRoutes(): void
442469
443470 static ::processMiddleware ($ event );
444471
445- // Process route requests with mcp middleware
446472 foreach ($ event ->routeRequests () as $ callback ) {
447473 Route ::middleware ('mcp ' )->group ($ callback );
448474 }
475+
476+ static ::refreshRoutes ();
449477 }
450478
451479 /**
0 commit comments