Repository: EasyCorp/EasyAdminBundle (language: php)

Issue:
EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator::findRouteName(): Argument #2 ($crudControllerFqcn) must be of type string, null given
EasyAdmin Version: `>=4.21.1`

**Describe the bug**
> EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator::findRouteName(): Argument #2 ($crudControllerFqcn) must be of type string, null given

**To Reproduce**

```php
class DashboardControllerTest extends AdminTestCase
{
    public function testIndex(): void
    {
        static::createAuthenticatedClient(UsersFixture::SUPER_ADMIN_EMAIL);
        $this->client->request(Request::METHOD_GET, $this->generateIndexUrl());

        $this->assertResponseIsSuccessful();
    }
}
```



Discussion / hints:
Do you still have this bug with the latest release?
> Do you still have this bug with the latest release?

@Seb33300 , sorry, I forgot to mention the version. The bug appeared with the latest release: before the test worked (`<=4.20.7`).
I also get the same error in smoke tests all the time even with version 4.22.0.
I confirm, too, that the issue is present also on the very last release, `4.22.0`.

Fix patch:
diff --git a/src/Router/AdminRouteGenerator.php b/src/Router/AdminRouteGenerator.php
index cf639eb63a..35bf1e76d6 100644
--- a/src/Router/AdminRouteGenerator.php
+++ b/src/Router/AdminRouteGenerator.php
@@ -94,11 +94,16 @@ public function usesPrettyUrls(): bool
         return $this->applicationUsesPrettyUrls ??= $this->filesystem->exists(sprintf('%s/%s', $this->buildDir, AdminRouteLoader::PRETTY_URLS_CONTEXT_FILE_NAME));
     }
 
-    public function findRouteName(string $dashboardFqcn, string $crudControllerFqcn, string $actionName): ?string
+    public function findRouteName(?string $dashboardFqcn = null, ?string $crudControllerFqcn = null, ?string $actionName = null): ?string
     {
         $adminRoutes = $this->cache->getItem(self::CACHE_KEY_FQCN_TO_ROUTE)->get();
 
-        return $adminRoutes[$dashboardFqcn][$crudControllerFqcn][$actionName] ?? null;
+        if (null === $dashboardFqcn) {
+            $dashboardControllers = iterator_to_array($this->dashboardControllers);
+            $dashboardFqcn = $dashboardControllers[array_key_first($dashboardControllers)]::class;
+        }
+
+        return $adminRoutes[$dashboardFqcn][$crudControllerFqcn ?? ''][$actionName ?? ''] ?? null;
     }
 
     /**


Test patch:
diff --git a/tests/Router/AdminRouteGeneratorTest.php b/tests/Router/AdminRouteGeneratorTest.php
new file mode 100644
index 0000000000..5b5e2b439b
--- /dev/null
+++ b/tests/Router/AdminRouteGeneratorTest.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace EasyCorp\Bundle\EasyAdminBundle\Tests\Router;
+
+use EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator;
+use EasyCorp\Bundle\EasyAdminBundle\Tests\PrettyUrlsTestApplication\Controller\BlogPostCrudController;
+use EasyCorp\Bundle\EasyAdminBundle\Tests\PrettyUrlsTestApplication\Controller\CategoryCrudController;
+use EasyCorp\Bundle\EasyAdminBundle\Tests\PrettyUrlsTestApplication\Controller\DashboardController;
+use EasyCorp\Bundle\EasyAdminBundle\Tests\PrettyUrlsTestApplication\Controller\SecondDashboardController;
+use Psr\Cache\CacheItemPoolInterface;
+use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+use Symfony\Component\Cache\CacheItem;
+use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
+use Symfony\Component\Filesystem\Filesystem;
+
+class AdminRouteGeneratorTest extends WebTestCase
+{
+    use ExpectDeprecationTrait;
+
+    /**
+     * @dataProvider provideFindRouteData
+     */
+    public function testFindRoute(?string $dashboardControllerFqcn, ?string $crudControllerFqcn, ?string $action, ?string $expectedRouteName)
+    {
+        $client = static::createClient();
+        $cacheMock = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock();
+        $cacheMock->method('getItem')->willReturnCallback(function ($key) {
+            $item = new CacheItem();
+            $item->expiresAfter(3600);
+
+            if (AdminRouteGenerator::CACHE_KEY_FQCN_TO_ROUTE !== $key) {
+                return $item;
+            }
+
+            $item->set([
+                DashboardController::class => [
+                    '' => [
+                        '' => 'admin',
+                    ],
+                    BlogPostCrudController::class => [
+                        'index' => 'admin_post_index',
+                        'new' => 'admin_post_new',
+                        'edit' => 'admin_post_edit',
+                        'detail' => 'admin_post_detail',
+                    ],
+                ],
+                SecondDashboardController::class => [
+                    '' => [
+                        '' => 'second_admin',
+                    ],
+                ],
+            ]);
+
+            return $item;
+        });
+
+        $dashboardControllers = new RewindableGenerator(function () {
+            yield DashboardController::class => new DashboardController();
+            yield SecondDashboardController::class => new SecondDashboardController();
+        }, 2);
+
+        $adminRouteGenerator = new AdminRouteGenerator(
+            $dashboardControllers,
+            [],
+            $cacheMock,
+            new Filesystem(),
+            $client->getKernel()->getBuildDir(),
+        );
+
+        $routeName = $adminRouteGenerator->findRouteName($dashboardControllerFqcn, $crudControllerFqcn, $action);
+        $this->assertSame($expectedRouteName, $routeName);
+    }
+
+    public function provideFindRouteData(): iterable
+    {
+        yield [null, null, null, 'admin'];
+        yield [DashboardController::class, null, null, 'admin'];
+        yield [DashboardController::class, BlogPostCrudController::class, null, null];
+        yield [DashboardController::class, BlogPostCrudController::class, 'index', 'admin_post_index'];
+        yield [DashboardController::class, BlogPostCrudController::class, 'detail', 'admin_post_detail'];
+        yield [DashboardController::class, CategoryCrudController::class, null, null];
+        yield [DashboardController::class, CategoryCrudController::class, 'index', null];
+        yield [DashboardController::class, CategoryCrudController::class, 'detail', null];
+        yield [SecondDashboardController::class, null, null, 'second_admin'];
+        yield [SecondDashboardController::class, BlogPostCrudController::class, null, null];
+        yield [SecondDashboardController::class, BlogPostCrudController::class, 'index', null];
+        yield [SecondDashboardController::class, BlogPostCrudController::class, 'detail', null];
+    }
+}