Commit 0d2a45ad authored by catch's avatar catch

Issue #2930715 by alexpott, dawehner: Recursive rebuild caused by installing...

Issue #2930715 by alexpott, dawehner: Recursive rebuild caused by installing admin_toolbar_tools module
parent 7f00c341
......@@ -803,6 +803,8 @@ services:
router.route_provider.lazy_builder:
class: Drupal\Core\Routing\RouteProviderLazyBuilder
arguments: ['@router.route_provider', '@router.builder']
tags:
- { name: event_subscriber }
router.route_preloader:
class: Drupal\Core\Routing\RoutePreloader
arguments: ['@router.route_provider', '@state', '@cache.bootstrap']
......
......@@ -3,12 +3,13 @@
namespace Drupal\Core\Routing;
use Symfony\Cmf\Component\Routing\PagedRouteProviderInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* A Route Provider front-end for all Drupal-stored routes.
*/
class RouteProviderLazyBuilder implements PreloadableRouteProviderInterface, PagedRouteProviderInterface {
class RouteProviderLazyBuilder implements PreloadableRouteProviderInterface, PagedRouteProviderInterface, EventSubscriberInterface {
/**
* The route provider service.
......@@ -31,6 +32,18 @@ class RouteProviderLazyBuilder implements PreloadableRouteProviderInterface, Pag
*/
protected $rebuilt = FALSE;
/**
* Flag to determine if router is currently being rebuilt.
*
* Used to prevent recursive router rebuilds during module installation.
* Recursive rebuilds can occur when route information is required by alter
* hooks that are triggered during a rebuild, for example,
* hook_menu_links_discovered_alter().
*
* @var bool
*/
protected $rebuilding = FALSE;
/**
* RouteProviderLazyBuilder constructor.
*
......@@ -51,7 +64,7 @@ public function __construct(RouteProviderInterface $route_provider, RouteBuilder
* The route provider service.
*/
protected function getRouteProvider() {
if (!$this->rebuilt) {
if (!$this->rebuilt && !$this->rebuilding) {
$this->routeBuilder->rebuild();
$this->rebuilt = TRUE;
}
......@@ -132,4 +145,27 @@ public function hasRebuilt() {
return $this->rebuilt;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[RoutingEvents::DYNAMIC][] = ['routerRebuilding', 3000];
$events[RoutingEvents::FINISHED][] = ['routerRebuildFinished', -3000];
return $events;
}
/**
* Sets the router rebuilding flag to TRUE.
*/
public function routerRebuilding() {
$this->rebuilding = TRUE;
}
/**
* Sets the router rebuilding flag to FALSE.
*/
public function routerRebuildFinished() {
$this->rebuilding = FALSE;
}
}
<?php
/**
* @file
* Helper module for the lazy route provider tests.
*/
/**
* Implements hook_menu_links_discovered_alter().
*/
function lazy_route_provider_install_test_menu_links_discovered_alter(&$links) {
$message = \Drupal::state()->get(__FUNCTION__, 'success');
try {
// Ensure that calling this does not cause a recursive rebuild.
\Drupal::service('router.route_provider')->getAllRoutes();
}
catch (\RuntimeException $e) {
$message = 'failed';
}
\Drupal::state()->set(__FUNCTION__, $message);
}
......@@ -23,6 +23,11 @@ public function testInstallation() {
// we cannot use ::assertEquals().
$this->assertStringEndsWith('/admin', \Drupal::state()->get('Drupal\lazy_route_provider_install_test\PluginManager'));
$this->assertStringEndsWith('/router_test/test1', \Drupal::state()->get('router_test_install'));
// If there is an exception thrown in rebuilding a route then the state
// 'lazy_route_provider_install_test_menu_links_discovered_alter' will be
// set.
// @see lazy_route_provider_install_test_menu_links_discovered_alter().
$this->assertEquals('success', \Drupal::state()->get('lazy_route_provider_install_test_menu_links_discovered_alter', NULL));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment