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

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions