Repository: EasyCorp/EasyAdminBundle (language: php)

Issue:
MenuItemMatcher breaks foreach loop, before processing all menu items
**Describe the bug**
I've updated from 4.10.3 to 4.11.0 and got issues with selected menu items.

The break in foreach loop https://github.com/EasyCorp/EasyAdminBundle/blob/4.x/src/Menu/MenuItemMatcher.php#L96 does prevent that any MenuItem but the first get processed. Therefore no item (except the first) is marked as selected, when active.

First the usermenu is processed (it has three items) and all three got processed. But the main menu with 31 items, get stuck after the first item, as described before. I'm not sure why it works for the user menu, but not for my main menu - but it seems that a break in foreach when `[] === $menuItemQueryParameters || [] === $currentPageQueryParameters` is true, is not correct.

**To Reproduce**
These are my first records in `configureMenuItems()` method, in DashboardController:

```
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
yield MenuItem::linkToRoute('Das Team', 'fa fa-users', 'hub_team');

yield MenuItem::section('Projekte');
yield MenuItem::linkToCrud('Projekte', 'far fa-gem', Project::class)->setPermission('ROLE_USER')->setController(ProjectCrudController::class);
// ...
```
Only "Dashboard" get selected when on `/`, "Das Team" does never selected, even when I'm on `/?routeName=hub_team`.


Discussion / hints:
Side note: I can reconstruct this issue in DDEV environment, shipped with EasyAdmin

Also, when I removed all "breaks" in the `doMarkSelectedMenuItem` method, it works as expected. But I don't know if this has other side effects
I ran into the same issue this morning.

Looks like for efficiency purposes it's `break`ing when it sets selected to true but it does so erroneously in the case you mentioned.

It should check that at least one was set to selected before that break.

Functionally this, but prettier:
```
            if ([] === $menuItemQueryParameters || [] === $currentPageQueryParameters) {
                $anySet = false;
                if ($menuItemDto->getLinkUrl() === $currentRequestUri) {
                    $menuItemDto->setSelected(true);
                    $anySet = true;
                }
                if ($anySet) {
                    break;
                }
            }
```
same here. I think the break should be inside the inner if
```
            if ([] === $menuItemQueryParameters || [] === $currentPageQueryParameters) {
                if ($menuItemDto->getLinkUrl() === $currentRequestUri) {
                    $menuItemDto->setSelected(true);

                    break;
                }
            }
```

I was able to provide a unit test, which covers the issue:
```php
public function testMenuWithDashboardItem()
{
    $dashboardMenuItem = new MenuItemDto();
    $dashboardMenuItem->setLabel('Dashboard');
    $dashboardMenuItem->setType(MenuItemDto::TYPE_DASHBOARD);

    $menuItems = [
        $dashboardMenuItem,
        $this->getMenuItemDto(label: 'Team', routeName: 'hub_team'),
    ];

    $request = $this->getRequestMock(
        routeName: 'hub_team',
    );

    $menuItemMatcher = new MenuItemMatcher();
    $menuItems = $menuItemMatcher->markSelectedMenuItem($menuItems, $request);

    $this->assertSame('Team', $this->getSelectedMenuItemLabel($menuItems), 'Perfect match: Dashboard item');
}
```
Currently, this test will fail:
> 1) EasyCorp\Bundle\EasyAdminBundle\Tests\Menu\MenuItemMatcherTest::testMenuWithDashboardItem
> Perfect match: Dashboard item
> Failed asserting that null is identical to 'Team'.

So the issue only appears, with Dashboard menu items, which have no route params set.

Fix patch:
diff --git a/src/Menu/MenuItemMatcher.php b/src/Menu/MenuItemMatcher.php
index 0cdcce1cd3..e45face3f5 100644
--- a/src/Menu/MenuItemMatcher.php
+++ b/src/Menu/MenuItemMatcher.php
@@ -93,7 +93,7 @@ private function doMarkSelectedMenuItem(array $menuItems, Request $request): arr
                     $menuItemDto->setSelected(true);
                 }
 
-                break;
+                continue;
             }
 
             // if the menu only contains links to the INDEX action of the CRUD controller,


Test patch:
diff --git a/tests/Menu/MenuItemMatcherTest.php b/tests/Menu/MenuItemMatcherTest.php
index 9a6cd24c71..7aad1e9e5c 100644
--- a/tests/Menu/MenuItemMatcherTest.php
+++ b/tests/Menu/MenuItemMatcherTest.php
@@ -149,6 +149,27 @@ public function testIsSelectedWithUrls()
         $this->assertTrue($menuItemDto->isSelected(), 'The URL matches');
     }
 
+    public function testMenuWithDashboardItem()
+    {
+        $dashboardMenuItem = new MenuItemDto();
+        $dashboardMenuItem->setLabel('item1');
+        $dashboardMenuItem->setType(MenuItemDto::TYPE_DASHBOARD);
+
+        $menuItems = [
+            $dashboardMenuItem,
+            $this->getMenuItemDto(label: 'item2', routeName: 'item2'),
+        ];
+
+        $request = $this->getRequestMock(
+            routeName: 'item2',
+        );
+
+        $menuItemMatcher = new MenuItemMatcher();
+        $menuItems = $menuItemMatcher->markSelectedMenuItem($menuItems, $request);
+
+        $this->assertSame('item2', $this->getSelectedMenuItemLabel($menuItems), 'Perfect match: Dashboard item');
+    }
+
     public function testComplexMenu()
     {
         $menuItems = $this->getComplexMenuItems();