diff --git a/core/core.services.yml b/core/core.services.yml index bffe0aa..daaad96 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -298,7 +298,7 @@ services: arguments: ['@database'] router.builder: class: Drupal\Core\Routing\RouteBuilder - arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler'] + arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver'] path.alias_manager.cached: class: Drupal\Core\CacheDecorator\AliasManagerCacheDecorator arguments: ['@path.alias_manager', '@cache.path'] diff --git a/core/lib/Drupal/Core/EventSubscriber/AccessRouteSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/AccessRouteSubscriber.php index 1ce500e..dee7d32 100644 --- a/core/lib/Drupal/Core/EventSubscriber/AccessRouteSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/AccessRouteSubscriber.php @@ -53,7 +53,7 @@ public function onRoutingRouteAlterSetAccessCheck(RouteBuildEvent $event) { */ static function getSubscribedEvents() { // Setting very low priority to ensure access checks are run after alters. - $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetAccessCheck', -50); + $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetAccessCheck', -1000); return $events; } diff --git a/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php index 9c52ed1..6283dae 100644 --- a/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php @@ -72,7 +72,7 @@ public function onRoutingRouteAlterSetType(RouteBuildEvent $event) { * {@inheritdoc} */ static function getSubscribedEvents() { - $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetType', 100); + $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetType', -150); return $events; } } diff --git a/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php index f9a0a69..7d385f5 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ParamConverterSubscriber.php @@ -49,7 +49,7 @@ public function onRoutingRouteAlterSetParameterConverters(RouteBuildEvent $event * {@inheritdoc} */ static function getSubscribedEvents() { - $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetParameterConverters', 10); + $events[RoutingEvents::ALTER][] = array('onRoutingRouteAlterSetParameterConverters', -200); return $events; } } diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php index cf28ebd..0581ebc 100644 --- a/core/lib/Drupal/Core/Routing/RouteBuilder.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Routing; use Drupal\Component\Discovery\YamlDiscovery; +use Drupal\Core\Controller\ControllerResolverInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Yaml\Parser; use Symfony\Component\Routing\RouteCollection; @@ -60,6 +61,13 @@ class RouteBuilder { protected $moduleHandler; /** + * The controller resolver. + * + * @var \Drupal\Core\Controller\ControllerResolverInterface + */ + protected $controllerResolver; + + /** * Construcs the RouteBuilder using the passed MatcherDumperInterface. * * @param \Drupal\Core\Routing\MatcherDumperInterface $dumper @@ -70,12 +78,15 @@ class RouteBuilder { * The event dispatcher to notify of routes. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver + * The controller resolver. */ - public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler) { + public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler, ControllerResolverInterface $controller_resolver) { $this->dumper = $dumper; $this->lock = $lock; $this->dispatcher = $dispatcher; $this->moduleHandler = $module_handler; + $this->controllerResolver = $controller_resolver; } /** @@ -98,6 +109,17 @@ public function rebuild() { foreach ($yaml_discovery->findAll() as $provider => $routes) { $collection = new RouteCollection(); + if (isset($routes['route_callbacks'])) { + foreach ($routes['route_callbacks'] as $route_callback) { + $callback = $this->controllerResolver->getControllerFromDefinition($route_callback); + if ($callback_routes = call_user_func($callback)) { + foreach ($callback_routes as $name => $callback_route) { + $collection->add($name, $callback_route); + } + } + } + unset($routes['route_callbacks']); + } foreach ($routes as $name => $route_info) { $route_info += array( 'defaults' => array(), @@ -116,7 +138,6 @@ public function rebuild() { // Now allow modules to register additional, dynamic routes. $collection = new RouteCollection(); - $this->dispatcher->dispatch(RoutingEvents::DYNAMIC, new RouteBuildEvent($collection, 'dynamic_routes')); $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection, 'dynamic_routes')); $this->dumper->addRoutes($collection); $this->dumper->dump(array('provider' => 'dynamic_routes')); diff --git a/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php b/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php index 82b2643..1172428 100644 --- a/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php +++ b/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php @@ -17,18 +17,6 @@ abstract class RouteSubscriberBase implements EventSubscriberInterface { /** - * Provides new routes by adding them to the collection. - * - * Subclasses should use this method and add \Symfony\Component\Routing\Route - * objects with $collection->add('route_name', $route);. - * - * @param \Symfony\Component\Routing\RouteCollection $collection - * The route collection for adding routes. - */ - protected function routes(RouteCollection $collection) { - } - - /** * Alters existing routes for a specific collection. * * @param \Symfony\Component\Routing\RouteCollection $collection @@ -44,23 +32,11 @@ protected function alterRoutes(RouteCollection $collection, $provider) { * {@inheritdoc} */ public static function getSubscribedEvents() { - $events[RoutingEvents::DYNAMIC] = 'onDynamicRoutes'; $events[RoutingEvents::ALTER] = 'onAlterRoutes'; return $events; } /** - * Delegates the route gathering to self::routes(). - * - * @param \Drupal\Core\Routing\RouteBuildEvent $event - * The route build event. - */ - public function onDynamicRoutes(RouteBuildEvent $event) { - $collection = $event->getRouteCollection(); - $this->routes($collection); - } - - /** * Delegates the route altering to self::alterRoutes(). * * @param \Drupal\Core\Routing\RouteBuildEvent $event diff --git a/core/lib/Drupal/Core/Routing/RoutingEvents.php b/core/lib/Drupal/Core/Routing/RoutingEvents.php index 3ca6ef6..2289e73 100644 --- a/core/lib/Drupal/Core/Routing/RoutingEvents.php +++ b/core/lib/Drupal/Core/Routing/RoutingEvents.php @@ -23,16 +23,4 @@ */ const ALTER = 'routing.route_alter'; - /** - * The DYNAMIC event is fired to allow modules to register additional routes. - * - * Most routes are static, an should be defined as such. Dynamic routes are - * only those whose existence changes depending on the state of the system - * at runtime, depending on configuration. - * - * @see \Drupal\Core\Routing\RouteBuildEvent - * - * @var string - */ - const DYNAMIC = 'routing.route_dynamic'; } diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php b/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php index ea4b406..537b186 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Routing/RouteSubscriber.php @@ -36,7 +36,13 @@ public function __construct(ConfigMapperManagerInterface $mapper_manager) { /** * {@inheritdoc} */ - public function routes(RouteCollection $collection) { + protected function alterRoutes(RouteCollection $collection, $provider) { + // Because ConfigMapperManagerInterface uses the route provider to determine + // the routes to add here this must only run during the dynamic alter stage. + if ($provider != 'dynamic_routes') { + return; + } + $mappers = $this->mapperManager->getMappers(); foreach ($mappers as $mapper) { $collection->add($mapper->getOverviewRouteName(), $mapper->getOverviewRoute()); diff --git a/core/modules/content_translation/content_translation.services.yml b/core/modules/content_translation/content_translation.services.yml index 764dd39..6b3dcbd 100644 --- a/core/modules/content_translation/content_translation.services.yml +++ b/core/modules/content_translation/content_translation.services.yml @@ -5,7 +5,7 @@ services: content_translation.subscriber: class: Drupal\content_translation\Routing\ContentTranslationRouteSubscriber - arguments: ['@content_translation.manager', '@router.route_provider'] + arguments: ['@content_translation.manager'] tags: - { name: event_subscriber } diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php index b36c654..2390090 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Routing/ContentTranslationRouteSubscriber.php @@ -8,12 +8,10 @@ namespace Drupal\content_translation\Routing; use Drupal\content_translation\ContentTranslationManagerInterface; -use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Routing\RouteSubscriberBase; use Drupal\Core\Routing\RoutingEvents; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\Exception\RouteNotFoundException; /** * Subscriber for entity translation routes. @@ -28,41 +26,23 @@ class ContentTranslationRouteSubscriber extends RouteSubscriberBase { protected $contentTranslationManager; /** - * The route provider. - * - * @var \Drupal\Core\Routing\RouteProviderInterface - */ - protected $routeProvider; - - /** * Constructs a ContentTranslationRouteSubscriber object. * * @param \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager * The content translation manager. - * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider - * The route provider. */ - public function __construct(ContentTranslationManagerInterface $content_translation_manager, RouteProviderInterface $route_provider) { + public function __construct(ContentTranslationManagerInterface $content_translation_manager) { $this->contentTranslationManager = $content_translation_manager; - $this->routeProvider = $route_provider; } /** * {@inheritdoc} */ - protected function routes(RouteCollection $collection) { + protected function alterRoutes(RouteCollection $collection, $provider) { foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type => $entity_info) { - // First try to get the route from the dynamic_routes collection. + // Try to get the route from the current collection. if (!$entity_route = $collection->get($entity_info['links']['canonical'])) { - // Then try to get the route from the route provider itself, checking - // all previous collections. - try { - $entity_route = $this->routeProvider->getRouteByName($entity_info['links']['canonical']); - } - // If the route was not found, skip this entity type. - catch (RouteNotFoundException $e) { - continue; - } + continue; } $path = $entity_route->getPath() . '/translations'; @@ -167,7 +147,7 @@ protected function routes(RouteCollection $collection) { */ public static function getSubscribedEvents() { $events = parent::getSubscribedEvents(); - $events[RoutingEvents::DYNAMIC] = array('onDynamicRoutes', -100); + $events[RoutingEvents::ALTER] = array('onAlterRoutes', -100); return $events; } diff --git a/core/modules/field_ui/field_ui.services.yml b/core/modules/field_ui/field_ui.services.yml index 10752b0..65111cc 100644 --- a/core/modules/field_ui/field_ui.services.yml +++ b/core/modules/field_ui/field_ui.services.yml @@ -1,7 +1,7 @@ services: field_ui.subscriber: class: Drupal\field_ui\Routing\RouteSubscriber - arguments: ['@entity.manager', '@router.route_provider'] + arguments: ['@entity.manager'] tags: - { name: event_subscriber } access_check.field_ui.view_mode: diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php index b703ed4..1a20aee 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Routing/RouteSubscriber.php @@ -8,10 +8,8 @@ namespace Drupal\field_ui\Routing; use Drupal\Core\Entity\EntityManagerInterface; -use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Routing\RouteSubscriberBase; use Drupal\Core\Routing\RoutingEvents; -use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -28,43 +26,25 @@ class RouteSubscriber extends RouteSubscriberBase { protected $manager; /** - * The route provider. - * - * @var \Drupal\Core\Routing\RouteProviderInterface - */ - protected $routeProvider; - - /** * Constructs a RouteSubscriber object. * * @param \Drupal\Core\Entity\EntityManagerInterface $manager * The entity type manager. - * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider - * The route provider. */ - public function __construct(EntityManagerInterface $manager, RouteProviderInterface $route_provider) { + public function __construct(EntityManagerInterface $manager) { $this->manager = $manager; - $this->routeProvider = $route_provider; } /** * {@inheritdoc} */ - protected function routes(RouteCollection $collection) { + protected function alterRoutes(RouteCollection $collection, $provider) { foreach ($this->manager->getDefinitions() as $entity_type => $entity_info) { $defaults = array(); if ($entity_info['fieldable'] && isset($entity_info['links']['admin-form'])) { - // First try to get the route from the dynamic_routes collection. + // Try to get the route from the current collection. if (!$entity_route = $collection->get($entity_info['links']['admin-form'])) { - // Then try to get the route from the route provider itself, checking - // all previous collections. - try { - $entity_route = $this->routeProvider->getRouteByName($entity_info['links']['admin-form']); - } - // If the route was not found, skip this entity type. - catch (RouteNotFoundException $e) { - continue; - } + continue; } $path = $entity_route->getPath(); @@ -155,7 +135,7 @@ protected function routes(RouteCollection $collection) { */ public static function getSubscribedEvents() { $events = parent::getSubscribedEvents(); - $events[RoutingEvents::DYNAMIC] = array('onDynamicRoutes', -100); + $events[RoutingEvents::ALTER] = array('onAlterRoutes', -100); return $events; } diff --git a/core/modules/image/image.routing.yml b/core/modules/image/image.routing.yml index cf358af..46dfb5d 100644 --- a/core/modules/image/image.routing.yml +++ b/core/modules/image/image.routing.yml @@ -68,3 +68,6 @@ image.effect_edit_form: _title: 'Edit image effect' requirements: _permission: 'administer image styles' + +route_callbacks: + - '\Drupal\image\Routing\ImageStyleRoutes::routes' diff --git a/core/modules/image/image.services.yml b/core/modules/image/image.services.yml index d9c14c6..1447e03 100644 --- a/core/modules/image/image.services.yml +++ b/core/modules/image/image.services.yml @@ -1,8 +1,4 @@ services: - image.route_subscriber: - class: Drupal\image\EventSubscriber\RouteSubscriber - tags: - - { name: 'event_subscriber' } path_processor.image_styles: class: Drupal\image\PathProcessor\PathProcessorImageStyles tags: diff --git a/core/modules/image/lib/Drupal/image/EventSubscriber/RouteSubscriber.php b/core/modules/image/lib/Drupal/image/Routing/ImageStyleRoutes.php similarity index 65% rename from core/modules/image/lib/Drupal/image/EventSubscriber/RouteSubscriber.php rename to core/modules/image/lib/Drupal/image/Routing/ImageStyleRoutes.php index 59fbb75..39b2379 100644 --- a/core/modules/image/lib/Drupal/image/EventSubscriber/RouteSubscriber.php +++ b/core/modules/image/lib/Drupal/image/Routing/ImageStyleRoutes.php @@ -5,28 +5,31 @@ * Contains \Drupal\image\EventSubscriber\RouteSubscriber. */ -namespace Drupal\image\EventSubscriber; +namespace Drupal\image\Routing; -use Drupal\Core\Routing\RouteSubscriberBase; use Symfony\Component\Routing\Route; -use Symfony\Component\Routing\RouteCollection; /** * Defines a route subscriber to register a url for serving image styles. */ -class RouteSubscriber extends RouteSubscriberBase { +class ImageStyleRoutes { /** - * {@inheritdoc} + * Returns an array of route objects. + * + * @return \Symfony\Component\Routing\Route[] + * An array of route objects. */ - protected function routes(RouteCollection $collection) { + public function routes() { + $routes = array(); // Generate image derivatives of publicly available files. If clean URLs are // disabled image derivatives will always be served through the menu system. // If clean URLs are enabled and the image derivative already exists, PHP // will be bypassed. $directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(); - $route = new Route('/' . $directory_path . '/styles/{image_style}/{scheme}', + $routes['image.style_public'] = new Route( + '/' . $directory_path . '/styles/{image_style}/{scheme}', array( '_controller' => 'Drupal\image\Controller\ImageStyleDownloadController::deliver', ), @@ -34,7 +37,7 @@ protected function routes(RouteCollection $collection) { '_access' => 'TRUE', ) ); - $collection->add('image.style_public', $route); + return $routes; } } diff --git a/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php b/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php similarity index 80% rename from core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php rename to core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php index e7d9ea3..ef1b93f 100644 --- a/core/modules/rest/lib/Drupal/rest/EventSubscriber/RouteSubscriber.php +++ b/core/modules/rest/lib/Drupal/rest/Routing/ResourceRoutes.php @@ -5,17 +5,17 @@ * Contains \Drupal\rest\EventSubscriber\RouteSubscriber. */ -namespace Drupal\rest\EventSubscriber; +namespace Drupal\rest\Routing; use Drupal\Core\Config\ConfigFactory; -use Drupal\Core\Routing\RouteSubscriberBase; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\rest\Plugin\Type\ResourcePluginManager; -use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Subscriber for REST-style routes. */ -class RouteSubscriber extends RouteSubscriberBase { +class ResourceRoutes implements ContainerInjectionInterface { /** * The plugin manager for REST plugins. @@ -47,7 +47,21 @@ public function __construct(ResourcePluginManager $manager, ConfigFactory $confi /** * {@inheritdoc} */ - protected function routes(RouteCollection $collection) { + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.rest'), + $container->get('config.factory') + ); + } + + /** + * Returns an array of route objects. + * + * @return \Symfony\Component\Routing\Route[] + * An array of route objects. + */ + public function routes() { + $routes = array(); $enabled_resources = $this->config->get('rest.settings')->load()->get('resources'); // Iterate over all enabled resource plugins. @@ -82,10 +96,11 @@ protected function routes(RouteCollection $collection) { // The configuration seems legit at this point, so we set the // authentication provider and add the route. $route->setOption('_auth', $enabled_methods[$method]['supported_auth']); - $collection->add("rest.$name", $route); + $routes["rest.$name"] = $route; } } } + return $routes; } } diff --git a/core/modules/rest/rest.routing.yml b/core/modules/rest/rest.routing.yml index 843dee9..3017130 100644 --- a/core/modules/rest/rest.routing.yml +++ b/core/modules/rest/rest.routing.yml @@ -4,3 +4,6 @@ rest.csrftoken: _controller: '\Drupal\rest\RequestHandler::csrfToken' requirements: _access: 'TRUE' + +route_callbacks: + - '\Drupal\rest\Routing\ResourceRoutes::routes' diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml index d238442..7c63426 100644 --- a/core/modules/rest/rest.services.yml +++ b/core/modules/rest/rest.services.yml @@ -9,11 +9,6 @@ services: factory_method: get factory_service: cache_factory arguments: [rest] - rest.route_subscriber: - class: Drupal\rest\EventSubscriber\RouteSubscriber - tags: - - { name: event_subscriber } - arguments: ['@plugin.manager.rest', '@config.factory'] access_check.rest.csrf: class: Drupal\rest\Access\CSRFAccessCheck tags: diff --git a/core/modules/search/lib/Drupal/search/Routing/SearchPluginRoutes.php b/core/modules/search/lib/Drupal/search/Routing/SearchPluginRoutes.php new file mode 100644 index 0000000..bfc37ea --- /dev/null +++ b/core/modules/search/lib/Drupal/search/Routing/SearchPluginRoutes.php @@ -0,0 +1,73 @@ +searchManager = $search_plugin_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.search') + ); + } + + /** + * Returns an array of route objects. + * + * @return \Symfony\Component\Routing\Route[] + * An array of route objects. + */ + public function routes() { + $routes = array(); + foreach ($this->searchManager->getActiveDefinitions() as $plugin_id => $search_info) { + $routes["search.view_$plugin_id"] = new Route( + 'search/' . $search_info['path'] . '/{keys}', + array( + '_content' => 'Drupal\search\Controller\SearchController::view', + '_title' => $search_info['title'], + 'plugin_id' => $plugin_id, + 'keys' => '', + ), + array( + 'keys' => '.+', + '_search_plugin_view_access' => $plugin_id, + '_permission' => 'search content', + ) + ); + } + return $routes; + } + +} diff --git a/core/modules/search/lib/Drupal/search/Routing/SearchRouteSubscriber.php b/core/modules/search/lib/Drupal/search/Routing/SearchRouteSubscriber.php deleted file mode 100644 index 258d8db..0000000 --- a/core/modules/search/lib/Drupal/search/Routing/SearchRouteSubscriber.php +++ /dev/null @@ -1,59 +0,0 @@ -searchManager = $search_plugin_manager; - } - - /** - * {@inheritdoc} - */ - protected function routes(RouteCollection $collection) { - foreach ($this->searchManager->getActiveDefinitions() as $plugin_id => $search_info) { - $path = 'search/' . $search_info['path'] . '/{keys}'; - $defaults = array( - '_content' => 'Drupal\search\Controller\SearchController::view', - '_title' => $search_info['title'], - 'plugin_id' => $plugin_id, - 'keys' => '', - ); - $requirements = array( - 'keys' => '.+', - '_search_plugin_view_access' => $plugin_id, - '_permission' => 'search content', - ); - $route = new Route($path, $defaults, $requirements); - $collection->add('search.view_' . $plugin_id, $route); - } - } - -} diff --git a/core/modules/search/search.routing.yml b/core/modules/search/search.routing.yml index 9502d77..a3247bc 100644 --- a/core/modules/search/search.routing.yml +++ b/core/modules/search/search.routing.yml @@ -25,3 +25,6 @@ search.view: keys: '.+' _permission: 'search content' _search_access: 'TRUE' + +route_callbacks: + - '\Drupal\search\Routing\SearchPluginRoutes::routes' diff --git a/core/modules/search/search.services.yml b/core/modules/search/search.services.yml index 88f6ea9..31dc5c5 100644 --- a/core/modules/search/search.services.yml +++ b/core/modules/search/search.services.yml @@ -14,9 +14,3 @@ services: arguments: ['@plugin.manager.search'] tags: - { name: access_check } - - route_subscriber.search: - class: Drupal\search\Routing\SearchRouteSubscriber - arguments: ['@plugin.manager.search'] - tags: - - { name: event_subscriber } diff --git a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php index e15ea62..25d3de0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Routing/RouterTest.php @@ -115,11 +115,6 @@ public function testControllerPlaceholdersDefaultValuesProvided() { * @see \Drupal\router_test\RouteSubscriber */ public function testDynamicRoutes() { - // Test the dynamically added route. - $this->drupalGet('router_test/test5'); - $this->assertResponse(200); - $this->assertRaw('test5', 'The correct string was returned because the route was successful.'); - // Test the altered route. $this->drupalGet('router_test/test6'); $this->assertResponse(200); diff --git a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml index 4bab92e..6905f23 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml +++ b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml @@ -22,3 +22,6 @@ entity_test.render_no_view_mode: _entity_view: 'entity_test' requirements: _access: 'TRUE' + +route_callbacks: + - '\Drupal\entity_test\Routing\EntityTestRoutes::routes' diff --git a/core/modules/system/tests/modules/entity_test/entity_test.services.yml b/core/modules/system/tests/modules/entity_test/entity_test.services.yml deleted file mode 100644 index 77855b8..0000000 --- a/core/modules/system/tests/modules/entity_test/entity_test.services.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - entity_test.subscriber: - class: Drupal\entity_test\Routing\RouteSubscriber - tags: - - { name: event_subscriber } diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/EntityTestRoutes.php similarity index 69% rename from core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php rename to core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/EntityTestRoutes.php index 91a43cd..7f608e6 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/EntityTestRoutes.php @@ -7,30 +7,31 @@ namespace Drupal\entity_test\Routing; -use Drupal\Core\Routing\RouteSubscriberBase; use Symfony\Component\Routing\Route; -use Symfony\Component\Routing\RouteCollection; /** * Subscriber for Entity Test routes. */ -class RouteSubscriber extends RouteSubscriberBase { +class EntityTestRoutes { /** - * {@inheritdoc} + * Returns an array of route objects. + * + * @return \Symfony\Component\Routing\Route[] + * An array of route objects. */ - protected function routes(RouteCollection $collection) { + public function routes() { $types = entity_test_entity_types(); + $routes = array(); foreach ($types as $entity_type) { - $route = new Route( + $routes["entity_test.add_$entity_type"] = new Route( "$entity_type/add", array('_content' => '\Drupal\entity_test\Controller\EntityTestController::testAdd', 'entity_type' => $entity_type), array('_permission' => 'administer entity_test content') ); - $collection->add("entity_test.add_$entity_type", $route); - $route = new Route( + $routes["entity_test.edit_$entity_type"] = new Route( "$entity_type/manage/{" . $entity_type . '}', array('_content' => '\Drupal\entity_test\Controller\EntityTestController::testEdit', '_entity_type' => $entity_type), array('_permission' => 'administer entity_test content'), @@ -38,15 +39,14 @@ protected function routes(RouteCollection $collection) { 'entity' => array('type' => 'entity:' . $entity_type), )) ); - $collection->add("entity_test.edit_$entity_type", $route); - $route = new Route( + $routes["entity_test.admin_$entity_type"] = new Route( "$entity_type/structure/{bundle}", array('_content' => '\Drupal\entity_test\Controller\EntityTestController::testAdmin'), array('_permission' => 'administer entity_test content') ); - $collection->add("entity_test.admin_$entity_type", $route); } + return $routes; } } diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml index f8467ff..de1ddea 100644 --- a/core/modules/system/tests/modules/form_test/form_test.routing.yml +++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml @@ -433,3 +433,11 @@ form_test.form_state_database: _title: 'Form state with a database connection' requirements: _access: 'TRUE' + +form_test.two_instances: + path: '/form-test/two-instances-of-same-form' + defaults: + _content: '\Drupal\form_test\Controller\FormTestController::twoFormInstances' + requirements: + _module_dependencies: 'node' + _permission: 'create page content' diff --git a/core/modules/system/tests/modules/form_test/form_test.services.yml b/core/modules/system/tests/modules/form_test/form_test.services.yml index e658fca..0201650 100644 --- a/core/modules/system/tests/modules/form_test/form_test.services.yml +++ b/core/modules/system/tests/modules/form_test/form_test.services.yml @@ -3,6 +3,5 @@ services: class: Drupal\form_test\FormTestServiceObject form_test.event_subscriber: class: Drupal\form_test\EventSubscriber\FormTestEventSubscriber - arguments: ['@module_handler'] tags: - { name: event_subscriber } diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/EventSubscriber/FormTestEventSubscriber.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/EventSubscriber/FormTestEventSubscriber.php index 552398b..d560f18 100644 --- a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/EventSubscriber/FormTestEventSubscriber.php +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/EventSubscriber/FormTestEventSubscriber.php @@ -7,32 +7,14 @@ namespace Drupal\form_test\EventSubscriber; -use Drupal\Core\Routing\RouteSubscriberBase; -use Drupal\Core\Routing\RoutingEvents; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Symfony\Component\Routing\Route; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\Routing\RouteCollection; /** * Test event subscriber to add new attributes to the request. */ -class FormTestEventSubscriber extends RouteSubscriberBase { - - /** - * The module handler. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface - */ - protected $moduleHandler; - - /** - * Constructs a FormTestController object. - */ - public function __construct(ModuleHandlerInterface $moduleHandler) { - $this->moduleHandler = $moduleHandler; - } +class FormTestEventSubscriber implements EventSubscriberInterface { /** * Adds custom attributes to the request object. @@ -51,23 +33,7 @@ public function onKernelRequest(GetResponseEvent $event) { */ public static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('onKernelRequest'); - $events[RoutingEvents::DYNAMIC] = 'onDynamicRoutes'; - $events[RoutingEvents::ALTER] = 'onAlterRoutes'; return $events; } - /** - * {@inheritdoc} - */ - protected function routes(RouteCollection $collection) { - if ($this->moduleHandler->moduleExists('node')) { - $route = new Route( - "form-test/two-instances-of-same-form", - array('_content' => '\Drupal\form_test\Controller\FormTestController::twoFormInstances'), - array('_permission' => 'create page content') - ); - $collection->add("form_test.two_instances", $route); - } - } - } diff --git a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php index e658b11..e342209 100644 --- a/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php +++ b/core/modules/system/tests/modules/router_test_directory/lib/Drupal/router_test/RouteTestSubscriber.php @@ -6,56 +6,23 @@ namespace Drupal\router_test; -use \Drupal\Core\Routing\RouteBuildEvent; -use \Drupal\Core\Routing\RoutingEvents; -use \Symfony\Component\EventDispatcher\EventSubscriberInterface; -use \Symfony\Component\Routing\Route; +use Drupal\Core\Routing\RouteSubscriberBase; +use Symfony\Component\Routing\RouteCollection; /** * Listens to the dynamic route event and add a test route. */ -class RouteTestSubscriber implements EventSubscriberInterface { +class RouteTestSubscriber extends RouteSubscriberBase { /** - * Implements EventSubscriberInterface::getSubscribedEvents(). + * {@inheritdoc} */ - static function getSubscribedEvents() { - $events[RoutingEvents::DYNAMIC] = 'dynamicRoutes'; - $events[RoutingEvents::ALTER] = 'alterRoutes'; - return $events; - } - - /** - * Adds a dynamic test route. - * - * @param \Drupal\Core\Routing\RouteBuildEvent $event - * The route building event. - */ - public function dynamicRoutes(RouteBuildEvent $event) { - $collection = $event->getRouteCollection(); - $route = new Route('/router_test/test5', array( - '_content' => '\Drupal\router_test\TestControllers::test5' - ), array( - '_access' => 'TRUE' - )); - $collection->add('router_test.5', $route); - } - - /** - * Alters an existing test route. - * - * @param \Drupal\Core\Routing\RouteBuildEvent $event - * The route building event. - * - * @return \Symfony\Component\Routing\RouteCollection - * The altered route collection. - */ - public function alterRoutes(RouteBuildEvent $event) { - if ($event->getProvider() == 'router_test') { - $collection = $event->getRouteCollection(); + protected function alterRoutes(RouteCollection $collection, $provider) { + if ($provider == 'router_test') { $route = $collection->get('router_test.6'); // Change controller method from test1 to test5. $route->setDefault('_controller', '\Drupal\router_test\TestControllers::test5'); } } + } diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php index c8b0437..5768dd3 100644 --- a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php +++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php @@ -97,7 +97,7 @@ protected function getViewsDisplayIDsWithRoute() { /** * {@inheritdoc} */ - protected function routes(RouteCollection $collection) { + protected function alterRoutes(RouteCollection $collection, $provider) { foreach ($this->getViewsDisplayIDsWithRoute() as $pair) { list($view_id, $display_id) = explode('.', $pair); $view = $this->viewStorageController->load($view_id); @@ -105,33 +105,14 @@ protected function routes(RouteCollection $collection) { if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) { if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) { if ($display instanceof DisplayRouterInterface) { - $view_route_names = (array) $display->collectRoutes($collection); - - $this->viewRouteNames += $view_route_names; - } - } - $view->destroy(); - } - } - - $this->state->set('views.view_route_names', $this->viewRouteNames); - } + if ($provider == 'dynamic_routes') { + $this->viewRouteNames += (array) $display->collectRoutes($collection); + } - /** - * {@inheritdoc} - */ - protected function alterRoutes(RouteCollection $collection, $module) { - foreach ($this->getViewsDisplayIDsWithRoute() as $pair) { - list($view_id, $display_id) = explode('.', $pair); - $view = $this->viewStorageController->load($view_id); - // @todo This should have an executable factory injected. - if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) { - if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) { - if ($display instanceof DisplayRouterInterface) { // If the display returns TRUE a route item was found, so it does not // have to be added. $view_route_names = $display->alterRoutes($collection); - $this->viewRouteNames += $view_route_names; + $this->viewRouteNames = $view_route_names + $this->viewRouteNames; foreach ($view_route_names as $id_display => $route_name) { unset($this->viewsDisplayPairs[$id_display]); } @@ -140,6 +121,9 @@ protected function alterRoutes(RouteCollection $collection, $module) { $view->destroy(); } } + if ($provider == 'dynamic_routes') { + $this->state->set('views.view_route_names', $this->viewRouteNames); + } } /** diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php index 48c116e..a3f0f49 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php @@ -98,7 +98,7 @@ public function testPageResponses() { public function testPageRouterItems() { $subscriber = new RouteSubscriber($this->container->get('entity.manager'), $this->container->get('state')); $collection = new RouteCollection(); - $subscriber->onDynamicRoutes(new RouteBuildEvent($collection, 'dynamic_routes')); + $subscriber->onAlterRoutes(new RouteBuildEvent($collection, 'dynamic_routes')); // Check the controller defaults. foreach ($collection as $id => $route) { diff --git a/core/modules/views/tests/Drupal/views/Tests/EventSubscriber/RouteSubscriberTest.php b/core/modules/views/tests/Drupal/views/Tests/EventSubscriber/RouteSubscriberTest.php index 6e4c644..64f9c5a 100644 --- a/core/modules/views/tests/Drupal/views/Tests/EventSubscriber/RouteSubscriberTest.php +++ b/core/modules/views/tests/Drupal/views/Tests/EventSubscriber/RouteSubscriberTest.php @@ -73,43 +73,13 @@ protected function setUp() { } /** - * Tests the onDynamicRoutes method. - * - * @see \Drupal\views\EventSubscriber\RouteSubscriber::onDynamicRoutes() - */ - public function testDynamicRoutes() { - $collection = new RouteCollection(); - $route_event = new RouteBuildEvent($collection, 'views'); - - list($view, $executable, $display_1, $display_2) = $this->setupMocks(); - - $display_1->expects($this->once()) - ->method('collectRoutes') - ->will($this->returnValue(array('test_id.page_1' => 'views.test_id.page_1'))); - $display_2->expects($this->once()) - ->method('collectRoutes') - ->will($this->returnValue(array('test_id.page_2' => 'views.test_id.page_2'))); - - $this->assertNull($this->routeSubscriber->onDynamicRoutes($route_event)); - - $this->state->expects($this->once()) - ->method('set') - ->with('views.view_route_names', array('test_id.page_1' => 'views.test_id.page_1', 'test_id.page_2' => 'views.test_id.page_2')); - $this->routeSubscriber->destruct(); - } - - /** * Tests the onAlterRoutes method. * * @see \Drupal\views\EventSubscriber\RouteSubscriber::onAlterRoutes() */ public function testOnAlterRoutes() { $collection = new RouteCollection(); - $collection->add('test_route', new Route('test_route', array('_controller' => 'Drupal\Tests\Core\Controller\TestController'))); - $route_2 = new Route('test_route/example', array('_controller' => 'Drupal\Tests\Core\Controller\TestController')); - $collection->add('test_route_2', $route_2); - - $route_event = new RouteBuildEvent($collection, 'views'); + $route_event = new RouteBuildEvent($collection, 'dynamic_routes'); list($view, $executable, $display_1, $display_2) = $this->setupMocks(); @@ -118,8 +88,9 @@ public function testOnAlterRoutes() { $display_1->expects($this->once()) ->method('alterRoutes') ->will($this->returnValue(array('test_id.page_1' => 'test_route'))); - $display_1->expects($this->never()) - ->method('collectRoutes'); + $display_1->expects($this->once()) + ->method('collectRoutes') + ->will($this->returnValue(array('test_id.page_1' => 'views.test_id.page_1'))); $display_2->expects($this->once()) ->method('alterRoutes') @@ -130,11 +101,6 @@ public function testOnAlterRoutes() { $this->assertNull($this->routeSubscriber->onAlterRoutes($route_event)); - // Ensure that after the alterRoutes the collectRoutes method is just called - // once (not for page_1 anymore). - - $this->assertNull($this->routeSubscriber->onDynamicRoutes($route_event)); - $this->state->expects($this->once()) ->method('set') ->with('views.view_route_names', array('test_id.page_1' => 'test_route', 'test_id.page_2' => 'views.test_id.page_2')); diff --git a/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php b/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php index 6b93d3b..9ea2165 100644 --- a/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php @@ -68,6 +68,13 @@ class RouteBuilderTest extends UnitTestCase { */ protected $moduleHandler; + /** + * The controller resolver. + * + * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $controllerResolver; + public static function getInfo() { return array( 'name' => 'Route Builder', @@ -81,11 +88,12 @@ protected function setUp() { $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); $this->dispatcher = $this->getMock('\Symfony\Component\EventDispatcher\EventDispatcherInterface'); $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); + $this->controllerResolver = $this->getMock('Drupal\Core\Controller\ControllerResolverInterface'); $this->yamlDiscovery = $this->getMockBuilder('\Drupal\Component\Discovery\YamlDiscovery') ->disableOriginalConstructor() ->getMock(); - $this->routeBuilder = new TestRouteBuilder($this->dumper, $this->lock, $this->dispatcher, $this->moduleHandler); + $this->routeBuilder = new TestRouteBuilder($this->dumper, $this->lock, $this->dispatcher, $this->moduleHandler, $this->controllerResolver); $this->routeBuilder->setYamlDiscovery($this->yamlDiscovery); } @@ -157,13 +165,9 @@ public function testRebuildWithStaticModuleRoutes() { $empty_collection = new RouteCollection(); $route_build_event = new RouteBuildEvent($empty_collection, 'dynamic_routes'); - // Ensure that the dynamic routes events are fired. + // Ensure that the alter routes events are fired. $this->dispatcher->expects($this->at(1)) ->method('dispatch') - ->with(RoutingEvents::DYNAMIC, $route_build_event); - - $this->dispatcher->expects($this->at(2)) - ->method('dispatch') ->with(RoutingEvents::ALTER, $route_build_event); // Ensure that the routes are set to the dumper and dumped. @@ -180,16 +184,15 @@ public function testRebuildWithStaticModuleRoutes() { ->method('dump') ->with(array('provider' => 'dynamic_routes')); - $this->assertTrue($this->routeBuilder->rebuild()); } /** - * Tests the rebuild with some dynamic routes. + * Tests the rebuild with routes provided by a callback. * * @see \Drupal\Core\Routing\RouteBuilder::rebuild() */ - public function testRebuildWithDynamicRoutes() { + public function testRebuildWithProviderBasedRoutes() { $this->lock->expects($this->once()) ->method('acquire') ->with('router_rebuild') @@ -197,28 +200,45 @@ public function testRebuildWithDynamicRoutes() { $this->yamlDiscovery->expects($this->once()) ->method('findAll') - ->will($this->returnValue(array())); + ->will($this->returnValue(array( + 'test_module' => array( + 'route_callbacks' => array( + '\Drupal\Tests\Core\Routing\TestRouteSubscriber::routes', + ), + ), + ))); + + $this->controllerResolver->expects($this->any()) + ->method('getControllerFromDefinition') + ->will($this->returnCallback(function ($controller) { + list($class, $method) = explode('::', $controller, 2); + $controller = new $class(); + return array($controller, $method); + })); $route_collection_filled = new RouteCollection(); $route_collection_filled->add('test_route', new Route('/test-route')); + // Ensure that the dispatch events for altering are fired. $this->dispatcher->expects($this->at(0)) ->method('dispatch') - ->with($this->equalTo(RoutingEvents::DYNAMIC)) - ->will($this->returnCallback(function ($object, RouteBuildEvent $event) { - $event->getRouteCollection()->add('test_route', new Route('/test-route')); - })); + ->with($this->equalTo(RoutingEvents::ALTER), $this->isInstanceOf('Drupal\Core\Routing\RouteBuildEvent')); + + $empty_collection = new RouteCollection(); + $route_build_event = new RouteBuildEvent($empty_collection, 'dynamic_routes'); + // Ensure that the alter routes events are fired. $this->dispatcher->expects($this->at(1)) ->method('dispatch') - ->with($this->equalTo(RoutingEvents::ALTER)); + ->with(RoutingEvents::ALTER, $route_build_event); - $this->dumper->expects($this->once()) + // Ensure that the routes are set to the dumper and dumped. + $this->dumper->expects($this->at(0)) ->method('addRoutes') ->with($route_collection_filled); - $this->dumper->expects($this->once()) + $this->dumper->expects($this->at(1)) ->method('dump') - ->with(array('provider' => 'dynamic_routes')); + ->with(array('provider' => 'test_module')); $this->assertTrue($this->routeBuilder->rebuild()); } @@ -241,3 +261,14 @@ public function setYamlDiscovery(YamlDiscovery $yaml_discovery) { } } + +/** + * Provides a callback for route definition. + */ +class TestRouteSubscriber { + public function routes() { + return array( + 'test_route' => new Route('/test-route'), + ); + } +}