diff --git a/core/core.services.yml b/core/core.services.yml index 7d56112..d3210f2 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -316,6 +316,11 @@ services: tags: - { name: paramconverter } arguments: ['@entity.manager'] + route_subscriber.module: + class: Drupal\Core\EventSubscriber\ModuleRouteSubscriber + tags: + - { name: event_subscriber } + arguments: ['@module_handler'] route_subscriber.entity: class: Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber tags: diff --git a/core/interdiff-2091411-24.txt b/core/interdiff-2091411-24.txt new file mode 100644 index 0000000..2eb62c9 --- /dev/null +++ b/core/interdiff-2091411-24.txt @@ -0,0 +1,121 @@ +diff --git a/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php +index df8a5f7..94c790c 100644 +--- a/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php ++++ b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php +@@ -50,16 +50,50 @@ public static function getSubscribedEvents() { + */ + public function removeRoutes(RouteBuildEvent $event) { + $collection = $event->getRouteCollection(); ++ + foreach ($collection as $name => $route) { +- if ($route->hasOption('_module_dependency')) { +- foreach ((array) $route->getOption('_module_dependency') as $module) { +- if (!$this->moduleHandler->moduleExists($module)) { ++ if ($route->hasRequirement('_module_dependencies')) { ++ $modules = $route->getRequirement('_module_dependencies'); ++ ++ $explode_and = $this->explodeString($modules, '+'); ++ if (count($explode_and) > 1) { ++ foreach ($explode_and as $module) { ++ // If any moduleExists() call returns FALSE, remove the route move ++ // onto the next. ++ if (!$this->moduleHandler->moduleExists($module)) { ++ $collection->remove($name); ++ break 2; ++ } ++ } ++ } ++ else { ++ foreach ($this->explodeString($modules, ',') as $module) { ++ $remove = TRUE; ++ if ($this->moduleHandler->moduleExists($module)) { ++ $remove = FALSE; ++ break; ++ } ++ } ++ // If no modules are found, remove the route. ++ if ($remove) { + $collection->remove($name); +- break; + } + } + } + } + } + ++ /** ++ * Explodes a string based on a separator. ++ * ++ * @param string $string ++ * @param string $separator ++ * ++ * @return array ++ * An array of exploded (and trimmed) values. ++ */ ++ protected function explodeString($string, $separator = ',') { ++ return array_filter(array_map('trim', explode($separator, $string))); ++ } ++ + } +diff --git a/core/modules/dblog/dblog.routing.yml b/core/modules/dblog/dblog.routing.yml +index ea66200..e72b84d 100644 +--- a/core/modules/dblog/dblog.routing.yml ++++ b/core/modules/dblog/dblog.routing.yml +@@ -34,6 +34,6 @@ dblog.search: + _content: '\Drupal\dblog\Controller\DbLogController::search' + _title: 'Top search phrases' + options: +- _module_dependency: ['search'] ++ _module_dependencies: 'search' + requirements: + _permission: 'access site reports' +diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php +index 501363d..5fcbfd2 100644 +--- a/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php ++++ b/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php +@@ -51,26 +51,34 @@ public function testRemoveRoute() { + ->will($this->returnValueMap($value_map)); + + $collection = new RouteCollection(); +- $route_1 = new Route('', array(), array(), array('_module_dependency' => array('enabled'))); ++ $route_1 = new Route('', array(), array('_module_dependencies' => 'enabled')); + $collection->add('enabled', $route_1); +- $route_2 = new Route('module_disabled', array(), array(), array('_module_dependency' => array('disabled'))); ++ $route_2 = new Route('', array(), array('_module_dependencies' => 'disabled')); + $collection->add('disabled', $route_2); +- $route_3 = new Route('module_disabled_first', array(), array(), array('_module_dependency' => array('disabled', 'enabled'))); +- $collection->add('disabled_first', $route_3); +- $route_4 = new Route('module_disabled_second', array(), array(), array('_module_dependency' => array('enabled', 'disabled'))); +- $collection->add('disabled_second', $route_4); +- $route_5 = new Route('no_module_dependency', array(), array(), array()); +- $collection->add('no_module_dependency', $route_5); ++ $route_3 = new Route('', array(), array('_module_dependencies' => 'disabled,enabled')); ++ $collection->add('enabled_or', $route_3); ++ $route_4 = new Route('', array(), array('_module_dependencies' => 'disabled,disabled')); ++ $collection->add('disabled_or', $route_4); ++ $route_5 = new Route('', array(), array('_module_dependencies' => 'disabled+disabled')); ++ $collection->add('disabled_and', $route_5); ++ $route_6 = new Route('', array(), array('_module_dependencies' => 'enabled+enabled')); ++ $collection->add('enabled_and', $route_6); ++ $route_7 = new Route(''); ++ $collection->add('no_module_dependencies', $route_7); + + $event = new RouteBuildEvent($collection, 'test'); + $route_subscriber = new ModuleRouteSubscriber($module_handler); + $route_subscriber->removeRoutes($event); + + $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled')); ++ $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled_or')); ++ $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled_and')); ++ + $this->assertNull($collection->get('disabled')); +- $this->assertNull($collection->get('disabled_first')); +- $this->assertNull($collection->get('disabled_second')); +- $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('no_module_dependency')); ++ $this->assertNull($collection->get('disabled_or')); ++ $this->assertNull($collection->get('disabled_and')); ++ ++ $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('no_module_dependencies')); + } + + } diff --git a/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php new file mode 100644 index 0000000..94c790c --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/ModuleRouteSubscriber.php @@ -0,0 +1,99 @@ +moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[RoutingEvents::ALTER] = 'removeRoutes'; + return $events; + } + + /** + * Removes any routes that have an unmet module dependency. + * + * @param \Drupal\Core\Routing\RouteBuildEvent $event + * The route building event. + */ + public function removeRoutes(RouteBuildEvent $event) { + $collection = $event->getRouteCollection(); + + foreach ($collection as $name => $route) { + if ($route->hasRequirement('_module_dependencies')) { + $modules = $route->getRequirement('_module_dependencies'); + + $explode_and = $this->explodeString($modules, '+'); + if (count($explode_and) > 1) { + foreach ($explode_and as $module) { + // If any moduleExists() call returns FALSE, remove the route move + // onto the next. + if (!$this->moduleHandler->moduleExists($module)) { + $collection->remove($name); + break 2; + } + } + } + else { + foreach ($this->explodeString($modules, ',') as $module) { + $remove = TRUE; + if ($this->moduleHandler->moduleExists($module)) { + $remove = FALSE; + break; + } + } + // If no modules are found, remove the route. + if ($remove) { + $collection->remove($name); + } + } + } + } + } + + /** + * Explodes a string based on a separator. + * + * @param string $string + * @param string $separator + * + * @return array + * An array of exploded (and trimmed) values. + */ + protected function explodeString($string, $separator = ',') { + return array_filter(array_map('trim', explode($separator, $string))); + } + +} diff --git a/core/modules/dblog/dblog.routing.yml b/core/modules/dblog/dblog.routing.yml index 31f1b1c..e72b84d 100644 --- a/core/modules/dblog/dblog.routing.yml +++ b/core/modules/dblog/dblog.routing.yml @@ -27,3 +27,13 @@ dblog.access_denied: _content: '\Drupal\dblog\Controller\DbLogController::accessDenied' requirements: _permission: 'access site reports' + +dblog.search: + path: '/admin/reports/search' + defaults: + _content: '\Drupal\dblog\Controller\DbLogController::search' + _title: 'Top search phrases' + options: + _module_dependencies: 'search' + requirements: + _permission: 'access site reports' diff --git a/core/modules/dblog/dblog.services.yml b/core/modules/dblog/dblog.services.yml deleted file mode 100644 index 815734c..0000000 --- a/core/modules/dblog/dblog.services.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - dblog.route_subscriber: - class: Drupal\dblog\Routing\RouteSubscriber - arguments: ['@module_handler'] - tags: - - { name: event_subscriber} diff --git a/core/modules/dblog/lib/Drupal/dblog/Routing/RouteSubscriber.php b/core/modules/dblog/lib/Drupal/dblog/Routing/RouteSubscriber.php deleted file mode 100644 index f04492e..0000000 --- a/core/modules/dblog/lib/Drupal/dblog/Routing/RouteSubscriber.php +++ /dev/null @@ -1,73 +0,0 @@ -moduleHandler = $module_handler; - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() { - $events[RoutingEvents::DYNAMIC] = 'routes'; - return $events; - } - - /** - * Generate dynamic routes for various dblog pages. - * - * @param \Drupal\Core\Routing\RouteBuildEvent $event - * The route building event. - * - * @return \Symfony\Component\Routing\RouteCollection - * The route collection that contains the new dynamic route. - */ - public function routes(RouteBuildEvent $event) { - $collection = $event->getRouteCollection(); - if ($this->moduleHandler->moduleExists('search')) { - // The block entity listing page. - $route = new Route( - 'admin/reports/search', - array( - '_content' => '\Drupal\dblog\Controller\DbLogController::search', - '_title' => 'Top search phrases', - ), - array( - '_permission' => 'access site reports', - ) - ); - $collection->add('dblog.search', $route); - } - } - -} diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php new file mode 100644 index 0000000..5fcbfd2 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/EventSubscriber/ModuleRouteSubscriberTest.php @@ -0,0 +1,84 @@ + 'Module route subscriber', + 'description' => 'Unit test the \Drupal\Core\EventSubscriber\ModuleRouteSubscriber class.', + 'group' => 'System' + ); + } + + /** + * Tests that removeRoute() removes routes when the module is not enabled. + */ + public function testRemoveRoute() { + $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); + + $value_map = array( + array('enabled', TRUE), + array('disabled', FALSE), + ); + + $module_handler->expects($this->any()) + ->method('moduleExists') + ->will($this->returnValueMap($value_map)); + + $collection = new RouteCollection(); + $route_1 = new Route('', array(), array('_module_dependencies' => 'enabled')); + $collection->add('enabled', $route_1); + $route_2 = new Route('', array(), array('_module_dependencies' => 'disabled')); + $collection->add('disabled', $route_2); + $route_3 = new Route('', array(), array('_module_dependencies' => 'disabled,enabled')); + $collection->add('enabled_or', $route_3); + $route_4 = new Route('', array(), array('_module_dependencies' => 'disabled,disabled')); + $collection->add('disabled_or', $route_4); + $route_5 = new Route('', array(), array('_module_dependencies' => 'disabled+disabled')); + $collection->add('disabled_and', $route_5); + $route_6 = new Route('', array(), array('_module_dependencies' => 'enabled+enabled')); + $collection->add('enabled_and', $route_6); + $route_7 = new Route(''); + $collection->add('no_module_dependencies', $route_7); + + $event = new RouteBuildEvent($collection, 'test'); + $route_subscriber = new ModuleRouteSubscriber($module_handler); + $route_subscriber->removeRoutes($event); + + $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled')); + $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled_or')); + $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('enabled_and')); + + $this->assertNull($collection->get('disabled')); + $this->assertNull($collection->get('disabled_or')); + $this->assertNull($collection->get('disabled_and')); + + $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('no_module_dependencies')); + } + +}