EasyCorp / EasyCorp/EasyAdminBundle
AdminUrlGenerator loses filters/page/sort when generating a URL after a linkToRoute() action was generated in the same request
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 4.3k
- Forks
- 1.1k
- Avg merge
- 8d 2h
- Merged PRs (30d)
- 11
Description
Describe the bug
AdminUrlGenerator drops previously-set query parameters (filters, page, sort, query, batch-action params) when generating a URL for a linkToCrudAction()-based action, if that URL is generated after another action's URL was generated via linkToRoute() in the same request.
Concretely: on a filtered index page with a per-row action using linkToRoute() and a global action using linkToCrudAction() (e.g. a custom "export" action), the global action's rendered href is missing filters[...] entirely — even though every other link on the page (sort links, per-row links, the filters modal link) correctly keeps them.
To Reproduce
EasyAdmin v4.29.14.
- In a CRUD controller, add a per-row
Actionusing->linkToRoute('some_route', fn ($entity) => [...]). - Add a global
Actionusing->linkToCrudAction('someMethod')->createAsGlobalAction(). - Add a filter via
configureFilters(). - Visit the index page with the filter applied (e.g.
?crudAction=index&crudControllerFqcn=...&filters[status][comparison]=%21%3D&filters[status][value][0]=110). - Inspect the global action's rendered
href— it only containscrudAction/crudControllerFqcn, missingfilters[...].
(OPTIONAL) Additional context
Root cause: AdminUrlGenerator::generateUrl() ends with a reset that's needed so each URL generation starts fresh — the surrounding comment says so explicitly:
// this is important to start the generation of each URL from the same initial state
// otherwise, some parameters used when generating some URL could leak to other URLs
$this->isInitialized = false;
return $url;
But three earlier returns in the same method skip this reset, which seems to contradict that stated intent:
if ([] === $routeParameters) {
return $this->urlGenerator->generate($this->dashboardRoute, [], $urlType); // no reset
}
if (null !== $routeName = $this->get(EA::ROUTE_NAME)) {
$adminRoutes = $this->cache->getItem(AdminRouteGenerator::CACHE_KEY_ROUTE_TO_FQCN)->get();
if (null !== $adminRoutes && \array_key_exists($routeName, $adminRoutes)) {
return $this->urlGenerator->generate($routeName, $routeParameters[EA::ROUTE_PARAMS] ?? [], $urlType); // no reset
}
return $this->urlGenerator->generate($this->dashboardRoute, $routeParameters, $urlType); // no reset
}
The EA::ROUTE_NAME branch is exactly what linkToRoute()-based actions hit (via setRoute()->generateUrl()). Since $isInitialized stays true afterwards, the next unsetAllExcept()/get()/set() call on the same instance skips re-reading the current request and instead reuses the stale $this->routeParameters left over from that setRoute() call — which only has dashboardControllerFqcn/routeName/routeParams, no filters. This isn't limited to legacy/non-pretty-URL apps — the EA::ROUTE_NAME check happens before the pretty-URLs branching, so it affects both.
Suggested fix — add $this->isInitialized = false; before each early return:
--- a/src/Router/AdminUrlGenerator.php
+++ b/src/Router/AdminUrlGenerator.php
@@ -288,15 +288,21 @@ final class AdminUrlGenerator implements \Stringable, AdminUrlGeneratorInterface
if ([] === $routeParameters) {
+ $this->isInitialized = false;
+
return $this->urlGenerator->generate($this->dashboardRoute, [], $urlType);
}
if (null !== $routeName = $this->get(EA::ROUTE_NAME)) {
$adminRoutes = $this->cache->getItem(AdminRouteGenerator::CACHE_KEY_ROUTE_TO_FQCN)->get();
if (null !== $adminRoutes && \array_key_exists($routeName, $adminRoutes)) {
+ $this->isInitialized = false;
+
return $this->urlGenerator->generate($routeName, $routeParameters[EA::ROUTE_PARAMS] ?? [], $urlType);
}
+ $this->isInitialized = false;
+
return $this->urlGenerator->generate($this->dashboardRoute, $routeParameters, $urlType);
}
Verified locally (applied via cweagans/composer-patches) — fixes the issue.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/Router/AdminUrlGenerator.php, especially generateUrl() and its three early returns. Reproduce the described linkToRoute() then linkToCrudAction() sequence with an applied filter, and verify that generated URLs retain filters, pagination, sorting, query, and batch-action parameters after the fix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php, symfony
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100