Skip to content

Commit

Permalink
bug #6696 Fix an edge-case about pretty URLs and cache warm up (javie…
Browse files Browse the repository at this point in the history
…reguiluz)

This PR was merged into the 4.x branch.

Discussion
----------

Fix an edge-case about pretty URLs and cache warm up

Fixes #6680.

Thanks to the debugging information provided in #6680 I could implement this solution.

The first change is that we no longer use `Route` options but defaults, because defaults are mapped to `Request` attributes and the options are not available unless you instantiate the `Route` object, which is not possible in our scenario. This change simplifies code a bit.

The other change, and the real solution of the reported error, is that we know regenerate the admin route cache if we know that the backend uses pretty URLs but the cache doesn't contain the admin routes.

Commits
-------

3fdfe9e Fix an edge-case about pretty URLs and cache warm up
  • Loading branch information
javiereguiluz committed Jan 9, 2025
2 parents b614d15 + 3fdfe9e commit f813388
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 21 deletions.
1 change: 1 addition & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
->arg(3, service('router'))
->arg(4, service('router'))
->arg(5, service('cache.easyadmin'))
->arg(6, service(AdminRouteGenerator::class))
->tag('kernel.event_subscriber')

->set(ControllerFactory::class)
Expand Down
29 changes: 15 additions & 14 deletions src/EventListener/AdminRouterSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\CrudControllerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\DashboardControllerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Router\AdminRouteGeneratorInterface;
use EasyCorp\Bundle\EasyAdminBundle\Factory\AdminContextFactory;
use EasyCorp\Bundle\EasyAdminBundle\Factory\ControllerFactory;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminRouteGenerator;
Expand Down Expand Up @@ -38,15 +39,17 @@ class AdminRouterSubscriber implements EventSubscriberInterface
private UrlGeneratorInterface $urlGenerator;
private RequestMatcherInterface $requestMatcher;
private CacheItemPoolInterface $cache;
private AdminRouteGeneratorInterface $adminRouteGenerator;

public function __construct(AdminContextFactory $adminContextFactory, ControllerFactory $controllerFactory, ControllerResolverInterface $controllerResolver, UrlGeneratorInterface $urlGenerator, RequestMatcherInterface $requestMatcher, CacheItemPoolInterface $cache)
public function __construct(AdminContextFactory $adminContextFactory, ControllerFactory $controllerFactory, ControllerResolverInterface $controllerResolver, UrlGeneratorInterface $urlGenerator, RequestMatcherInterface $requestMatcher, CacheItemPoolInterface $cache, AdminRouteGenerator $adminRouteGenerator)
{
$this->adminContextFactory = $adminContextFactory;
$this->controllerFactory = $controllerFactory;
$this->controllerResolver = $controllerResolver;
$this->urlGenerator = $urlGenerator;
$this->requestMatcher = $requestMatcher;
$this->cache = $cache;
$this->adminRouteGenerator = $adminRouteGenerator;
}

public static function getSubscribedEvents(): array
Expand All @@ -64,32 +67,30 @@ public static function getSubscribedEvents(): array
public function onKernelRequestPrettyUrls(RequestEvent $event): void
{
$request = $event->getRequest();
$routeName = $request->attributes->get('_route');
if (null === $routeName) {
if (false === $request->attributes->has(EA::ROUTE_CREATED_BY_EASYADMIN)) {
return;
}

// edge-case: in some scenarios, admin routes are generated by the custom route loader
// and their information is cached but then removed from the cache (e.g. when running
// 'rm -fr var/cache/* && bin/console cache:clear'). If that's the case, regenerate the
// admin routes to force saving them in the cache again.
// see https://github.com/EasyCorp/EasyAdminBundle/issues/6680
$adminRoutes = $this->cache->getItem(AdminRouteGenerator::CACHE_KEY_ROUTE_TO_FQCN)->get();
if (null === $adminRoutes || !\array_key_exists($routeName, $adminRoutes)) {
return;
if (null === $adminRoutes) {
$this->adminRouteGenerator->generateAll();
}

$request->attributes->set(EA::ROUTE_CREATED_BY_EASYADMIN, true);

$dashboardControllerFqcn = $adminRoutes[$routeName][EA::DASHBOARD_CONTROLLER_FQCN];
$dashboardControllerFqcn = $request->attributes->get(EA::DASHBOARD_CONTROLLER_FQCN);
if (null === $dashboardControllerInstance = $this->getDashboardControllerInstance($dashboardControllerFqcn, $request)) {
return;
}

// creating the context is expensive, so it's created once and stored in the request
// if the current request already has an AdminContext object, do nothing
if (null === $adminContext = $request->attributes->get(EA::CONTEXT_REQUEST_ATTRIBUTE)) {
$crudControllerFqcn = $adminRoutes[$routeName][EA::CRUD_CONTROLLER_FQCN];
$actionName = $adminRoutes[$routeName][EA::CRUD_ACTION];

$request->attributes->set(EA::DASHBOARD_CONTROLLER_FQCN, $dashboardControllerFqcn);
$request->attributes->set(EA::CRUD_CONTROLLER_FQCN, $crudControllerFqcn);
$request->attributes->set(EA::CRUD_ACTION, $actionName);
$crudControllerFqcn = $request->attributes->get(EA::CRUD_CONTROLLER_FQCN);
$actionName = $request->attributes->get(EA::CRUD_ACTION);

$crudControllerInstance = $this->controllerFactory->getCrudControllerInstance($crudControllerFqcn, $actionName, $request);
$adminContext = $this->adminContextFactory->create($request, $dashboardControllerInstance, $crudControllerInstance, $actionName);
Expand Down
12 changes: 5 additions & 7 deletions src/Router/AdminRouteGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,13 @@ private function generateAdminRoutes(): array

$defaults = [
'_controller' => $crudControllerFqcn.'::'.$actionName,
];
$options = [
EA::ROUTE_CREATED_BY_EASYADMIN => true,
EA::DASHBOARD_CONTROLLER_FQCN => $dashboardFqcn,
EA::CRUD_CONTROLLER_FQCN => $crudControllerFqcn,
EA::CRUD_ACTION => $actionName,
];

$adminRoute = new Route($adminRoutePath, defaults: $defaults, options: $options, methods: $actionRouteConfig['methods']);
$adminRoute = new Route($adminRoutePath, defaults: $defaults, methods: $actionRouteConfig['methods']);
$adminRoutes[$adminRouteName] = $adminRoute;
$addedRouteNames[] = $adminRouteName;
}
Expand Down Expand Up @@ -397,12 +395,12 @@ private function saveAdminRoutesInCache(array $adminRoutes): void
// then, add all the generated admin routes
foreach ($adminRoutes as $routeName => $route) {
$routeNameToFqcn[$routeName] = [
EA::DASHBOARD_CONTROLLER_FQCN => $route->getOption(EA::DASHBOARD_CONTROLLER_FQCN),
EA::CRUD_CONTROLLER_FQCN => $route->getOption(EA::CRUD_CONTROLLER_FQCN),
EA::CRUD_ACTION => $route->getOption(EA::CRUD_ACTION),
EA::DASHBOARD_CONTROLLER_FQCN => $route->getDefault(EA::DASHBOARD_CONTROLLER_FQCN),
EA::CRUD_CONTROLLER_FQCN => $route->getDefault(EA::CRUD_CONTROLLER_FQCN),
EA::CRUD_ACTION => $route->getDefault(EA::CRUD_ACTION),
];

$fqcnToRouteName[$route->getOption(EA::DASHBOARD_CONTROLLER_FQCN)][$route->getOption(EA::CRUD_CONTROLLER_FQCN)][$route->getOption(EA::CRUD_ACTION)] = $routeName;
$fqcnToRouteName[$route->getDefault(EA::DASHBOARD_CONTROLLER_FQCN)][$route->getDefault(EA::CRUD_CONTROLLER_FQCN)][$route->getDefault(EA::CRUD_ACTION)] = $routeName;
}

$routeNameToFqcnItem = $this->cache->getItem(self::CACHE_KEY_ROUTE_TO_FQCN);
Expand Down

0 comments on commit f813388

Please sign in to comment.