diff -u b/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php --- b/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -11,6 +11,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterNestedMatchersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterRouteLoadersPass; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -73,8 +74,13 @@ $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder') ->addArgument(new Reference('router.dumper')) ->addArgument(new Reference('lock')) + // Placeholder argument replaced with services tagged 'route_loader' by + // the RegisterRouteLoadersPass compiler pass. + ->addArgument(array()) ->addArgument(new Reference('dispatcher')); - + $container->register('router.loader.yaml', 'Drupal\Core\Routing\YamlRouteLoader') + ->addTag('route_loader'); + $container->addCompilerPass(new RegisterRouteLoadersPass()); $container->register('matcher', 'Drupal\Core\Routing\ChainMatcher'); $container->register('legacy_url_matcher', 'Drupal\Core\LegacyUrlMatcher') diff -u b/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php --- b/core/lib/Drupal/Core/Routing/RouteBuilder.php +++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php @@ -9,9 +9,7 @@ use Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Yaml\Parser; use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\Route; use Drupal\Core\Lock\LockBackendInterface; @@ -38,6 +36,16 @@ protected $lock; /** + * An array of \Drupal\Core\Routing\RouteLoaderInterface objects. + * + * During route rebuilding, each loader is invoked for each enabled Drupal + * module. + * + * @var array $loaders + */ + protected $loaders; + + /** * The event dispatcher to notify of routes. * * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface @@ -51,12 +59,15 @@ * The matcher dumper used to store the route information. * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock backend. + * @param array $loaders + * An array of \Drupal\Core\Routing\RouteLoaderInterface objects. * @param \Symfony\Component\EventDispatcherEventDispatcherInterface * The event dispatcher to notify of routes. */ - public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher) { + public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, array $loaders, EventDispatcherInterface $dispatcher) { $this->dumper = $dumper; $this->lock = $lock; + $this->loaders = $loaders; $this->dispatcher = $dispatcher; } @@ -72,38 +83,20 @@ return; } - $parser = new Parser(); - // We need to manually call each module so that we can know which module // a given item came from. // @todo Use an injected Extension service rather than module_list(): // http://drupal.org/node/1331486. foreach (module_list() as $module) { $collection = new RouteCollection(); - $routing_file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . '/' . $module . '.routing.yml'; - if (file_exists($routing_file)) { - $routes = $parser->parse(file_get_contents($routing_file)); - if (!empty($routes)) { - foreach ($routes as $name => $route_info) { - $defaults = isset($route_info['defaults']) ? $route_info['defaults'] : array(); - $requirements = isset($route_info['requirements']) ? $route_info['requirements'] : array(); - $route = new Route($route_info['pattern'], $defaults, $requirements); - $collection->add($name, $route); - } - } + foreach ($this->loaders as $loader) { + $collection->addCollection($loader->getRouteCollection($module)); } - $this->dispatcher->dispatch(RoutingEvents::ALTER, new RouteBuildEvent($collection, $module)); + $this->dispatcher->dispatch('routing.alter', new RouteBuildEvent($collection, $module)); $this->dumper->addRoutes($collection); $this->dumper->dump(array('route_set' => $module)); } - // 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('route_set' => 'dynamic_routes')); - $this->lock->release('router_rebuild'); } reverted: --- b/core/lib/Drupal/Core/Routing/RoutingEvents.php +++ /dev/null @@ -1,38 +0,0 @@ -register('router.builder', 'Drupal\Core\Routing\RouteBuilder') ->addArgument(new Reference('router.dumper')) ->addArgument(new Reference('lock')) + ->addArgument(array()) ->addArgument(new Reference('dispatcher')); // Turn error reporting back on. From now on, only fatal errors (which are only in patch2: unchanged: --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteLoadersPass.php @@ -0,0 +1,65 @@ +getDefinition('router.builder'); + + // Retrieve registered route loaders from the container. + foreach ($container->findTaggedServiceIds('route_loader') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $loaders[$priority][] = new Reference($id); + } + + // Add the registered loaders to the route builder as the 3rd argument. + if (!empty($loaders)) { + $definition->replaceArgument(2, $this->sort($loaders)); + } + } + + /** + * Sorts by priority. + * + * Order services from highest priority number to lowest (reverse sorting). + * + * @param array $services + * A nested array keyed on priority number. For each priority number, the + * value is an array of Symfony\Component\DependencyInjection\Reference + * objects, each a reference to a route loader service. + * + * @return array + * A flattened array of Reference objects from $services, ordered from high + * to low priority. + */ + protected function sort($services) { + $sorted = array(); + krsort($services); + + // Flatten the array. + foreach ($services as $a) { + $sorted = array_merge($sorted, $a); + } + + return $sorted; + } +} only in patch2: unchanged: --- /dev/null +++ b/core/lib/Drupal/Core/Routing/RouteLoaderInterface.php @@ -0,0 +1,25 @@ +parse(file_get_contents($routing_file)); + if (!empty($routes)) { + foreach ($routes as $name => $route_info) { + $defaults = isset($route_info['defaults']) ? $route_info['defaults'] : array(); + $requirements = isset($route_info['requirements']) ? $route_info['requirements'] : array(); + $route = new Route($route_info['pattern'], $defaults, $requirements); + $collection->add($name, $route); + } + } + } + return $collection; + } + +}