Skip to content

[Bug] AdminRouteLoader ignores directory/host isolation in multi-dashboard setups #7411

@ben29

Description

@ben29

Describe the bug

When implementing multiple Dashboards intended for different subdomains (e.g., admin.site.com and aff.site.com), the AdminRouteLoader using type: easyadmin.routes creates a global collision.

Despite the dashboards being located in separate physical directories and namespaces, the loader performs a global discovery of all AbstractDashboardController instances. This causes the routes for the Admin dashboard to "leak" and be generated for the Affiliate subdomain host context, and vice versa.

Environment
PHP: 8.5
Symfony: 8.0
EasyAdmin Bundle: 4.28.0

To Reproduce
Project Structure
I have organized the controllers into separate directories to maintain strict isolation,
but the automatic route loader ignores these boundaries:

src/
└── Controller/
├── Admin/
│ └── AdminDashboardController.php --> (Target: admin.site.com)
└── Aff/
└── AffDashboardController.php --> (Target: aff.site.com)

routes.yaml

easyadmin:
    resource: .
    type: easyadmin.routes

AdminDashboardController.php:

#[AdminDashboard(
    routePath: '/dashboard', 
    routeName: 'admin', 
    routeOptions: ['host' => 'admin.%site_url%'],
    routes: [
        'index' => ['routeName' => 'index', 'routePath' => '/'],
        // ...
    ]
)]
final class AdminDashboardController extends AbstractDashboardController { ... }

AffDashboardController.php

#[AdminDashboard(
    routePath: '/panel', 
    routeName: 'affiliate', 
    routeOptions: ['host' => 'aff.%site_url%'],
    routes: []
)]
class AffDashboardController extends AbstractDashboardController { ... }

The Issue:

In EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteLoader, the load() method executes:

public function load(mixed $resource, ?string $type = null): RouteCollection
{
    // ...
    return $this->adminRouteGenerator->generateAll();
}

Currently, there is no way to tell the loader to "Only generate routes for Dashboards found in this specific resource/path."

Expected Behavior

The route loader should respect the resource path provided in routes.yaml or allow an option to filter discovery by namespace/directory so that:

admin.site.com only contains routes belonging to AdminDashboardController.

aff.site.com only contains routes belonging to AffDashboardController.

Actual Behavior

The loader aggregates all Dashboards and CRUD controllers into a single collection, causing Admin CRUDs to be mounted onto the Affiliate Dashboard.

For example, running bin/console debug:router shows Admin password reset routes appearing under the Affiliate URL prefix (/panel):

admin_admin_reset_admin_password      GET|POST   /dashboard/admin/reset  (Correct)
affiliate_admin_reset_admin_password  GET|POST   /panel/admin/reset      (BUG: Admin controller leaked to Affiliate host)

Proposed Solution

Update AdminRouteLoader to respect the $resource parameter or an optional dashboard_controller configuration. This would allow for separate definitions in routes.yaml:

admin_panel_routes:
    resource: 'App\Controller\Admin'
    type: easyadmin.routes

affiliate_panel_routes:
    resource: 'App\Controller\Aff'
    type: easyadmin.routes

or filter the routes by namespace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions