diff --git a/core/core.services.yml b/core/core.services.yml index c43950f..06f1c6d 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -551,6 +551,8 @@ services: router.builder: class: Drupal\Core\Routing\RouteBuilder arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@access_manager.check_provider', '@cache.default'] + tags: + - { name: needs_destruction } menu.rebuild_subscriber: class: Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber arguments: ['@lock', '@plugin.manager.menu.link'] diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php index cc3e6a1..7af2c9f 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php @@ -189,8 +189,6 @@ public function getLocalTasksForRoute($route_name) { $children = $cache->data['children']; } else { - // Maybe some code asked to rebuild the routes, so rebuild the router - // as we rely on having proper existing routes in dynamic local tasks. $definitions = $this->getDefinitions(); // We build the hierarchy by finding all tabs that should // appear on the current route. diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php index 72ae0db..30409f2 100644 --- a/core/lib/Drupal/Core/Routing/RouteBuilder.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php @@ -13,6 +13,7 @@ use Drupal\Core\Controller\ControllerResolverInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Lock\LockBackendInterface; +use Drupal\Core\DestructableInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Routing\RouteCollection; @@ -21,7 +22,7 @@ /** * Managing class for rebuilding the router table. */ -class RouteBuilder implements RouteBuilderInterface { +class RouteBuilder implements RouteBuilderInterface, DestructableInterface { /** * The dumper to which we should send collected routes. @@ -80,6 +81,13 @@ class RouteBuilder implements RouteBuilderInterface { protected $building = FALSE; /** + * Flag that indiciates if we should rebuild at the end of the request. + * + * @var bool + */ + protected $rebuildNeeded = FALSE; + + /** * The check provider. * * @var \Drupal\Core\Access\CheckProviderInterface @@ -117,6 +125,13 @@ public function __construct(MatcherDumperInterface $dumper, LockBackendInterface /** * {@inheritdoc} */ + public function setRebuildNeeded() { + $this->rebuildNeeded = TRUE; + } + + /** + * {@inheritdoc} + */ public function rebuild() { if ($this->building) { throw new \RuntimeException('Recursive router rebuild detected.'); @@ -191,6 +206,7 @@ public function rebuild() { $this->building = FALSE; $this->routeCollection = NULL; + $this->rebuildNeeded = FALSE; return TRUE; } @@ -242,4 +258,13 @@ protected function getRouteDefinitions() { return $route_definitions; } + /** + * {@inheritdoc} + */ + public function destruct() { + if ($this->rebuildNeeded) { + $this->rebuild(); + } + } + } diff --git a/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php b/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php index 55e0987..533faa5 100644 --- a/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilderInterface.php @@ -18,6 +18,13 @@ public function rebuild(); /** + * Set the rebuild needed flag. + * + * Schedules a route rebuild when the RouteBuilder service is destructed. + */ + public function setRebuildNeeded(); + + /** * Returns the route collection during the rebuild. * * Don't use this function unless you really have to! Better pass along the diff --git a/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php index 8993eef..62ff668 100644 --- a/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilderStatic.php @@ -13,13 +13,6 @@ class RouteBuilderStatic implements RouteBuilderInterface { /** - * Marks a rebuild as being necessary. - * - * @var bool - */ - protected $rebuildNeeded = FALSE; - - /** * {@inheritdoc} */ public function rebuild() { @@ -27,6 +20,13 @@ public function rebuild() { // http://drupal.org/node/1987816. } + /** + * {@inheritdoc} + */ + public function setRebuildNeeded() { + $this->rebuildNeeded = TRUE; + } + public function getCollectionDuringRebuild() { return FALSE; } diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc index 44224d9..58dceb9 100644 --- a/core/modules/content_translation/content_translation.admin.inc +++ b/core/modules/content_translation/content_translation.admin.inc @@ -337,5 +337,5 @@ function content_translation_form_language_content_settings_submit(array $form, // Ensure entity and menu router information are correctly rebuilt. \Drupal::entityManager()->clearCachedDefinitions(); - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index ac41f8e..c919b2d 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -610,7 +610,7 @@ function content_translation_language_configuration_element_submit(array $form, if (\Drupal::service('content_translation.manager')->isEnabled($context['entity_type'], $context['bundle']) != $enabled) { \Drupal::service('content_translation.manager')->setEnabled($context['entity_type'], $context['bundle'], $enabled); \Drupal::entityManager()->clearCachedDefinitions(); - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } } diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index 2a8fabd..413890b 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -105,7 +105,7 @@ function field_ui_entity_type_build(array &$entity_types) { function field_ui_entity_bundle_create($entity_type, $bundle) { // When a new bundle is created, the menu needs to be rebuilt to add our // menu item tabs. - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } /** @@ -114,7 +114,7 @@ function field_ui_entity_bundle_create($entity_type, $bundle) { function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) { // When a bundle is renamed, the menu needs to be rebuilt to add our // menu item tabs. - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } /** @@ -189,14 +189,14 @@ function field_ui_form_node_type_form_submit($form, FormStateInterface $form_sta * Implements hook_view_mode_presave(). */ function field_ui_view_mode_presave(EntityViewModeInterface $view_mode) { - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } /** * Implements hook_view_mode_delete(). */ function field_ui_view_mode_delete(EntityViewModeInterface $view_mode) { - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } /** diff --git a/core/modules/search/src/Entity/SearchPage.php b/core/modules/search/src/Entity/SearchPage.php index e11f76d..53c558e 100644 --- a/core/modules/search/src/Entity/SearchPage.php +++ b/core/modules/search/src/Entity/SearchPage.php @@ -184,7 +184,7 @@ public function postCreate(EntityStorageInterface $storage) { */ public function postSave(EntityStorageInterface $storage, $update = TRUE) { parent::postSave($storage, $update); - $this->routeBuilder()->rebuild(); + $this->routeBuilder()->setRebuildNeeded(); } /** diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index ed56d4e..7ea9365 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -724,7 +724,7 @@ function hook_entity_bundle_info_alter(&$bundles) { function hook_entity_bundle_create($entity_type_id, $bundle) { // When a new bundle is created, the menu needs to be rebuilt to add the // Field UI menu item tabs. - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } /** diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index 851402c..512c2e4 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -370,7 +370,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) { // Rebuild the router if this is a new view, or it's status changed. if (!isset($this->original) || ($this->status() != $this->original->status())) { - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); } } diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 707ad1f..da8168b 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -492,7 +492,7 @@ function views_invalidate_cache() { Cache::deleteTags(array('extension' => 'views')); // Set the menu as needed to be rebuilt. - \Drupal::service('router.builder')->rebuild(); + \Drupal::service('router.builder')->setRebuildNeeded(); $module_handler = \Drupal::moduleHandler();