Repository: EasyCorp/EasyAdminBundle (language: php)

Issue:
[`>=4.20.8`] Missing `active` CSS class on Dashboard route
**Describe the bug**
When accessing the Dashboard, the menù item is not highlighted as active anymore.

**To Reproduce**
Login in EasyAdmin: the Dashboard route is not highlighted.

**(OPTIONAL) Additional context**
Before `4.20.8`, the `li` tag had the css class `active`: it visually highlights the current route. This is missed only on Dashboard.

The problem seems in `\EasyCorp\Bundle\EasyAdminBundle\Dto\MenuItemDto::$selected`: the property is not set to `true` anymore and this prevents the template `menu.html.twig` to recognize the route as the active one:

https://github.com/EasyCorp/EasyAdminBundle/blob/b76eca4bae428b661c15bc95cbcee1ef569b722c/templates/menu.html.twig#L14

Digging deeper in the code, seems that this snippet caused the issue:

https://github.com/EasyCorp/EasyAdminBundle/blob/b76eca4bae428b661c15bc95cbcee1ef569b722c/src/EventListener/AdminRouterSubscriber.php#L69-L72

The route, infact, has the request attribute `routeCreatedByEasyAdmin` to `false`: this leads to the `return` and the `MenuItemDto` doesn't have property `active` set to `true`.

However, commenting the `return`, leads to an error, so this doesn't seem the right path to follow.

I'm not so versed in EasyAdmin to fix the issue and submit a PR: sorry 😔


Discussion / hints:
Yes, this is exactly the cause of the error. I'm working on a new nice feature related to pretty URLs that will indirectly fix this too.
@javiereguiluz , this issue is not fixed: I'm testing with 4.21.1 and the CSS class is still absent in the markup.

<img width="862" alt="Screenshot 2025-01-14 alle 09 40 06" src="https://github.com/user-attachments/assets/9086480a-b151-4c9c-911e-a0cc29f716f1" />

Maybe have I to update something else to make it work or the old configuration I have on 4.20.7 should be sufficient?

Fix patch:
diff --git a/config/services.php b/config/services.php
index e4fae73436..c3292a3ca4 100644
--- a/config/services.php
+++ b/config/services.php
@@ -235,6 +235,7 @@
 
         ->set(MenuItemMatcher::class)
             ->arg(0, service(AdminUrlGenerator::class))
+            ->arg(1, service(AdminRouteGenerator::class))
 
         ->alias(MenuItemMatcherInterface::class, MenuItemMatcher::class)
 
diff --git a/src/Menu/MenuItemMatcher.php b/src/Menu/MenuItemMatcher.php
index 1791a80286..d3187f32ed 100644
--- a/src/Menu/MenuItemMatcher.php
+++ b/src/Menu/MenuItemMatcher.php
@@ -7,6 +7,7 @@
 use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
 use EasyCorp\Bundle\EasyAdminBundle\Contracts\Menu\MenuItemMatcherInterface;
 use EasyCorp\Bundle\EasyAdminBundle\Dto\MenuItemDto;
+use EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator;
 use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -17,6 +18,7 @@ class MenuItemMatcher implements MenuItemMatcherInterface
 {
     public function __construct(
         private AdminUrlGenerator $adminUrlGenerator,
+        private AdminRouteGenerator $adminRouteGenerator,
     ) {
     }
 
@@ -35,8 +37,7 @@ public function __construct(
      */
     public function markSelectedMenuItem(array $menuItems, Request $request): array
     {
-        $usePrettyUrls = true === (bool) $request->attributes->get(EA::ROUTE_CREATED_BY_EASYADMIN);
-        if ($usePrettyUrls) {
+        if ($this->adminRouteGenerator->usesPrettyUrls()) {
             $menuItems = $this->doMarkSelectedPrettyUrlsMenuItem($menuItems, $request);
         } else {
             $menuItems = $this->doMarkSelectedLegacyMenuItem($menuItems, $request);


Test patch:
diff --git a/tests/Controller/PrettyUrls/PrettyUrlsControllerTest.php b/tests/Controller/PrettyUrls/PrettyUrlsControllerTest.php
index f83b89498a..e6def75420 100644
--- a/tests/Controller/PrettyUrls/PrettyUrlsControllerTest.php
+++ b/tests/Controller/PrettyUrls/PrettyUrlsControllerTest.php
@@ -297,7 +297,7 @@ public function testAdminUrlGenerator(): void
             ->setAction('customAction')
             ->generateUrl()
         ;
-       $client->request('GET', $url);
+        $client->request('GET', $url);
 
         $this->assertSelectorTextSame('#url1', 'http://localhost/admin/pretty/urls?'.http_build_query([
             'crudAction' => 'customAction',
@@ -305,7 +305,6 @@ public function testAdminUrlGenerator(): void
             'dashboardControllerFqcn' => DashboardController::class,
         ]));
 
-
         $this->assertSelectorTextSame('#url2', 'http://localhost/admin/pretty/urls?'.http_build_query([
             'crudAction' => 'customAction',
             'crudControllerFqcn' => CategoryCrudController::class,
diff --git a/tests/Menu/MenuItemMatcherTest.php b/tests/Menu/MenuItemMatcherTest.php
index 75c2944dd2..4f8e3ba90b 100644
--- a/tests/Menu/MenuItemMatcherTest.php
+++ b/tests/Menu/MenuItemMatcherTest.php
@@ -6,6 +6,7 @@
 use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
 use EasyCorp\Bundle\EasyAdminBundle\Dto\MenuItemDto;
 use EasyCorp\Bundle\EasyAdminBundle\Menu\MenuItemMatcher;
+use EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator;
 use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
 use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
 use Symfony\Component\HttpFoundation\InputBag;
@@ -19,7 +20,8 @@ public function testIsSelectedWhenContextIsNull()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItemDto = new MenuItemDto();
 
         $menuItemMatcher->markSelectedMenuItem([$menuItemDto], $request);
@@ -33,7 +35,8 @@ public function testIsSelectedWhenMenuItemIsSection()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItemDto = new MenuItemDto();
         $menuItemDto->setType(MenuItemDto::TYPE_SECTION);
 
@@ -50,7 +53,8 @@ public function testIsSelectedWithCrudControllers()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItemDto = $this->getMenuItemDto();
         $menuItemMatcher->markSelectedMenuItem([$menuItemDto], $request);
 
@@ -101,7 +105,8 @@ public function testIsSelectedWithRoutes()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItemDto = $this->getMenuItemDto(routeName: 'some_route');
 
         $menuItemMatcher->markSelectedMenuItem([$menuItemDto], $request);
@@ -142,7 +147,8 @@ public function testIsSelectedWithUrls()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItemDto = new MenuItemDto();
 
         $menuItemMatcher->markSelectedMenuItem([$menuItemDto], $request);
@@ -182,7 +188,8 @@ public function testMenuWithDashboardItem()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
         $menuItems = $menuItemMatcher->markSelectedMenuItem($menuItems, $request);
 
         $this->assertSame('item2', $this->getSelectedMenuItemLabel($menuItems), 'Perfect match: Dashboard item');
@@ -197,7 +204,8 @@ public function testComplexMenu()
 
         self::bootKernel();
         $adminUrlGenerator = self::getContainer()->get(AdminUrlGenerator::class);
-        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator);
+        $adminRouteGenerator = self::getContainer()->get(AdminRouteGenerator::class);
+        $menuItemMatcher = new MenuItemMatcher($adminUrlGenerator, $adminRouteGenerator);
 
         $menuItems = $menuItemMatcher->markSelectedMenuItem($menuItems, $request);