Skip to content

AdminUrlGenerator loses filters/page/sort when generating a URL after a linkToRoute() action was generated in the same request #7734

Open

Description

@LarsShift

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.

  1. In a CRUD controller, add a per-row Action using ->linkToRoute('some_route', fn ($entity) => [...]).
  2. Add a global Action using ->linkToCrudAction('someMethod')->createAsGlobalAction().
  3. Add a filter via configureFilters().
  4. Visit the index page with the filter applied (e.g. ?crudAction=index&crudControllerFqcn=...&filters[status][comparison]=%21%3D&filters[status][value][0]=110).
  5. Inspect the global action's rendered href — it only contains crudAction/crudControllerFqcn, missing filters[...].

(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.

Activity

  1. added this to the 5.x milestone on Jul 20, 2026
  2. added a commit that references this issue on Aug 16, 2026
    e3ce32e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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