Skip to content

Fix routes host - #7541

Open
Guilain wants to merge 1 commit into
EasyCorp:4.xfrom
SylApps:fix-routes-host
Open

Guilain wants to merge 1 commit into
EasyCorp:4.xfrom
SylApps:fix-routes-host

Conversation

@Guilain

@Guilain Guilain commented Apr 15, 2026

Copy link
Copy Markdown

Hello,

Updated: the host is now applied to all the routes generated for the dashboard, not just the dashboard route itself, and there are tests.

Today only the dashboard route gets the host, the CRUD and #[AdminRoute] routes match on any host. So you can't really run two dashboards on two hosts. With two dashboards on different hosts sharing the same route path:

host=backend.example.com  /host-admin                        => host_admin
host=backend.example.com  /host-admin/built-in-action/index  => host_admin_built_in_action_list
host=tenant.example.com   /host-admin                        => tenant_admin            (ok)
host=tenant.example.com   /host-admin/built-in-action/index  => host_admin_...          (wrong one)

You land on the right dashboard, then every page after that is served by the other one.
Absolute URLs have the same problem, they get the current host instead of the dashboard host, so an admin link sent by email points to the wrong domain.

@allan-simon had already suggested this in #6756:

Should the lines here
https://github.com/EasyCorp/EasyAdminBundle/blob/4.x/src/Router/AdminRouteGenerator.php#L245-L248
also take the host/defaults/requirements path ? so that it is then injected
automatically to all routes ?

The host is now applied to CRUD routes, to #[AdminRoute] on invokable controllers and to #[AdminRoute] on methods.

Parameterized hosts work too:

routeOptions: [
    'host' => '{subdomain}',
    'defaults' => ['subdomain' => '%admin_host%'],
    'requirements' => ['subdomain' => 'admin.*'],
]

The defaults and requirements of the host variables are inherited as well, otherwise the placeholder has no value and generating those URLs throws a MissingMandatoryParametersException. Only the ones actually used by the host are copied, the other dashboard defaults are left alone.

fix #7119, fix #6756

About #7411: it mixes two things, every CRUD controller being mounted on every dashboard, and routes not being isolated per host. This PR only does the second one. Discovery doesn't change, so allowedControllers / deniedControllers stay the way to pick which CRUD controllers a dashboard mounts, like @javiereguiluz said when closing it. They don't set any host on the generated routes though, so they can't separate two dashboards served from two hosts. In #7119 both use routePath: '/'.

Tests are in tests/Functional/AdminRoute/AdminRouteTest.php, I checked each one fails without the fix.

@ben29

ben29 commented May 2, 2026

Copy link
Copy Markdown

it's big issue that need to be fixed ASSAP...

@Guilain
Guilain force-pushed the fix-routes-host branch from a9d9fb0 to f39975d Compare May 21, 2026 08:42
@Seb33300

Seb33300 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What about this comment?
#7411 (comment)

Only the dashboard route was restricted to the host defined in the
routeOptions of the #[AdminDashboard] attribute. The CRUD and
#[AdminRoute] routes generated for that dashboard matched on any host,
so several dashboards could not be served from different hosts: when
they shared the same route path, every child page was served by
whichever dashboard was discovered first.

The host is now applied to the three kinds of generated routes: CRUD
action routes, #[AdminRoute] routes on invokable controllers and
#[AdminRoute] routes on controller methods. A host declared in the
options of an #[AdminRoute] attribute still takes precedence over the
dashboard one.

When the host is parameterized (e.g. '{subdomain}'), the defaults and
requirements of the variables it uses are inherited too, otherwise the
placeholder has no value and generating those URLs fails with a
MissingMandatoryParametersException. Only the defaults and requirements
of the variables used by the host are copied.

The host is also read from the legacy Symfony #[Route] attribute applied
to the index() method of the dashboard.
@Guilain

Guilain commented Aug 2, 2026

Copy link
Copy Markdown
Author

@Seb33300 the description was wrong on that, I've updated it.

#7411 mixes two problems: every CRUD controller being mounted on every dashboard, and the routes not being isolated per host.

allowedControllers / deniedControllers solve the first one, and this PR doesn't touch discovery at all. But they never set a host on the generated routes, so they can't separate two dashboards served from two hosts. In #7119 both use routePath: '/': whatever you filter, the routes still match on any host and the first ones found win.

That second part is what this PR fixes, and what #6756 and #7119 are about. It also helps #7411 a bit, the extra routes now carry the host of their dashboard so they're not served on the wrong domain anymore. Details and tests in the updated description.

@ben29

ben29 commented Aug 2, 2026

Copy link
Copy Markdown

Exactly!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants