class RouteBuilder in Drupal 10
Same name in this branch
- 10 core/lib/Drupal/Core/Routing/RouteBuilder.php \Drupal\Core\Routing\RouteBuilder
- 10 core/lib/Drupal/Core/ProxyClass/Routing/RouteBuilder.php \Drupal\Core\ProxyClass\Routing\RouteBuilder
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/Routing/RouteBuilder.php \Drupal\Core\Routing\RouteBuilder
- 9 core/lib/Drupal/Core/Routing/RouteBuilder.php \Drupal\Core\Routing\RouteBuilder
Managing class for rebuilding the router table.
Hierarchy
- class \Drupal\Core\Routing\RouteBuilder implements \Drupal\Core\Routing\RouteBuilderInterface, \Drupal\Core\DestructableInterface
Expanded class hierarchy of RouteBuilder
1 file declares its use of RouteBuilder
- InstallerRouteBuilder.php in core/
lib/ Drupal/ Core/ Installer/ InstallerRouteBuilder.php
1 string reference to 'RouteBuilder'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses RouteBuilder
File
- core/
lib/ Drupal/ Core/ Routing/ RouteBuilder.php, line 19
Namespace
Drupal\Core\RoutingView source
class RouteBuilder implements RouteBuilderInterface, DestructableInterface {
/**
* The dumper to which we should send collected routes.
*
* @var \Drupal\Core\Routing\MatcherDumperInterface
*/
protected $dumper;
/**
* The used lock backend instance.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lock;
/**
* The event dispatcher to notify of routes.
*
* @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface
*/
protected $dispatcher;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The controller resolver.
*
* @var \Drupal\Core\Controller\ControllerResolverInterface
*/
protected $controllerResolver;
/**
* The route collection during the rebuild.
*
* @var \Symfony\Component\Routing\RouteCollection
*/
protected $routeCollection;
/**
* Flag that indicates if we are currently rebuilding the routes.
*
* @var bool
*/
protected $building = FALSE;
/**
* Flag that indicates if we should rebuild at the end of the request.
*
* @var bool
*/
protected $rebuildNeeded = FALSE;
/**
* The check provider.
*
* @var \Drupal\Core\Access\CheckProviderInterface
*/
protected $checkProvider;
/**
* Constructs the RouteBuilder using the passed MatcherDumperInterface.
*
* @param \Drupal\Core\Routing\MatcherDumperInterface $dumper
* The matcher dumper used to store the route information.
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $dispatcher
* 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.
* @param \Drupal\Core\Access\CheckProviderInterface $check_provider
* The check provider.
*/
public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler, ControllerResolverInterface $controller_resolver, CheckProviderInterface $check_provider) {
$this->dumper = $dumper;
$this->lock = $lock;
$this->dispatcher = $dispatcher;
$this->moduleHandler = $module_handler;
$this->controllerResolver = $controller_resolver;
$this->checkProvider = $check_provider;
}
/**
* {@inheritdoc}
*/
public function setRebuildNeeded() {
$this->rebuildNeeded = TRUE;
}
/**
* {@inheritdoc}
*/
public function rebuild() {
if ($this->building) {
throw new \RuntimeException('Recursive router rebuild detected.');
}
if (!$this->lock
->acquire('router_rebuild')) {
// Wait for another request that is already doing this work.
// We choose to block here since otherwise the routes might not be
// available, resulting in a 404.
$this->lock
->wait('router_rebuild');
return FALSE;
}
$this->building = TRUE;
$collection = new RouteCollection();
foreach ($this
->getRouteDefinitions() as $routes) {
// The top-level 'routes_callback' is a list of methods in controller
// syntax, see \Drupal\Core\Controller\ControllerResolver. These methods
// should return a set of \Symfony\Component\Routing\Route objects, either
// in an associative array keyed by the route name, which will be iterated
// over and added to the collection for this provider, or as a new
// \Symfony\Component\Routing\RouteCollection object, which will be added
// to the collection.
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)) {
// If a RouteCollection is returned, add the whole collection.
if ($callback_routes instanceof RouteCollection) {
$collection
->addCollection($callback_routes);
}
else {
foreach ($callback_routes as $name => $callback_route) {
$collection
->add($name, $callback_route);
}
}
}
}
unset($routes['route_callbacks']);
}
foreach ($routes as $name => $route_info) {
$route_info += [
'defaults' => [],
'requirements' => [],
'options' => [],
'host' => NULL,
'schemes' => [],
'methods' => [],
'condition' => '',
];
// Ensure routes default to using Drupal's route compiler instead of
// Symfony's.
$route_info['options'] += [
'compiler_class' => RouteCompiler::class,
];
$route = new Route($route_info['path'], $route_info['defaults'], $route_info['requirements'], $route_info['options'], $route_info['host'], $route_info['schemes'], $route_info['methods'], $route_info['condition']);
$collection
->add($name, $route);
}
}
// DYNAMIC is supposed to be used to add new routes based upon all the
// static defined ones.
$this->dispatcher
->dispatch(new RouteBuildEvent($collection), RoutingEvents::DYNAMIC);
// ALTER is the final step to alter all the existing routes. We cannot stop
// people from adding new routes here, but we define two separate steps to
// make it clear.
$this->dispatcher
->dispatch(new RouteBuildEvent($collection), RoutingEvents::ALTER);
$this->checkProvider
->setChecks($collection);
$this->dumper
->addRoutes($collection);
$this->dumper
->dump();
$this->lock
->release('router_rebuild');
$this->dispatcher
->dispatch(new Event(), RoutingEvents::FINISHED);
$this->building = FALSE;
$this->rebuildNeeded = FALSE;
return TRUE;
}
/**
* {@inheritdoc}
*/
public function rebuildIfNeeded() {
if ($this->rebuildNeeded) {
return $this
->rebuild();
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function destruct() {
// Rebuild routes only once at the end of the request lifecycle to not
// trigger multiple rebuilds and also make the page more responsive for the
// user.
$this
->rebuildIfNeeded();
}
/**
* Retrieves all defined routes from .routing.yml files.
*
* @return array
* The defined routes, keyed by provider.
*/
protected function getRouteDefinitions() {
// Always instantiate a new YamlDiscovery object so that we always search on
// the up-to-date list of modules.
$discovery = new YamlDiscovery('routing', $this->moduleHandler
->getModuleDirectories());
return $discovery
->findAll();
}
}