Providing dynamic routes
This documentation needs work. See "Help improve this page" in the sidebar.
The simplest way to provide routes is to define them in a routing YAML file named after the module, as seen in the introductory example. Not all routes are static though, so it may not always be possible to specify in a static YAML file. Thankfully Drupal 8 provides a way to specify routes in a dynamic way as well.
Dynamic routes
Dynamic routes are implemented in a method. This method is added as a 'route_callbacks'
entry in example.routing.yml
:
route_callbacks:
- '\Drupal\example\Routing\ExampleRoutes::routes'
It's also possible to use a method on a service:
route_callbacks:
- 'example.service:routes'
Note: route_callbacks is a top-level element in the routing file. Here is an example from the views module:
views.ajax:
path: '/views/ajax'
defaults:
_controller: '\Drupal\views\Controller\ViewAjaxController::ajaxView'
requirements:
_access: 'TRUE'
route_callbacks:
- 'views.route_subscriber:routes'
The dynamic routing method either returns an array of \Symfony\Component\Routing\Route
objects or a \Symfony\Component\Routing\RouteCollection
object. A simple example could be a src/Routing/ExampleRoutes.php
file in your module (if the module is named example).
namespace Drupal\example\Routing;
use Symfony\Component\Routing\Route;
/**
* Defines dynamic routes.
*/
class ExampleRoutes {
/**
* Provides dynamic routes.
*/
public function routes() {
$routes = [];
// Declares a single route under the name 'example.content'.
// Returns an array of Route objects.
$routes['example.content'] = new Route(
// Path to attach this route to:
'/example',
// Route defaults:
[
'_controller' => '\Drupal\example\Controller\ExampleController::content',
'_title' => 'Hello',
],
// Route requirements:
[
'_permission' => 'access content',
]
);
return $routes;
}
}
Alternatively the dynamic route method can return a \Symfony\Component\Routing\RouteCollection
object. This example defines the same route as the example above.
namespace Drupal\example\Routing;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Defines dynamic routes.
*/
class ExampleRoutes {
/**
* Provides dynamic routes.
*/
public function routes() {
$route_collection = new RouteCollection();
$route = new Route(
// Path to attach this route to:
'/example',
// Route defaults:
[
'_controller' => '\Drupal\example\Controller\ExampleController::content',
'_title' => 'Hello',
],
// Route requirements:
[
'_permission' => 'access content',
]
);
// Add the route under the name 'example.content'.
$route_collection->add('example.content', $route);
return $route_collection;
}
}
This example reproduces the same route from the introductory example that is much simpler to define using the routing YAML file. Normally you would add dynamic routes with this method. Defining static routes is just painful this way. Use your own logic to derive those routes. Modules like Views, Image, and RESTful Web Services use this system to attach routes to all kinds of areas in Drupal core in a configurable way. The following is an example of the Image module in core in which the path is dynamically generated:
namespace Drupal\image\Routing;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
/**
* Defines a route subscriber to register a url for serving image styles.
*/
class ImageStyleRoutes implements ContainerInjectionInterface {
/**
* The stream wrapper manager service.
*
* @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
*/
protected $streamWrapperManager;
/**
* Constructs a new ImageStyleRoutes object.
*
* @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
* The stream wrapper manager service.
*/
public function __construct(StreamWrapperManagerInterface $stream_wrapper_manager) {
$this->streamWrapperManager = $stream_wrapper_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('stream_wrapper_manager')
);
}
/**
* Returns an array of route objects.
*
* @return \Symfony\Component\Routing\Route[]
* An array of route objects.
*/
public function routes() {
$routes = [];
// 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 = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath();
$routes['image.style_public'] = new Route(
'/' . $directory_path . '/styles/{image_style}/{scheme}',
[
'_controller' => 'Drupal\image\Controller\ImageStyleDownloadController::deliver',
],
[
'_access' => 'TRUE',
]
);
return $routes;
}
}
Dynamic routes based on other dynamic routes
You may need to define dynamic routes that may be based on other dynamic routes, such as you want to add tabs consistently on all the pages created by views. In this case, the above method will not work. You'll need to implement a service that responds to the onAlterRoutes
event. The documentation on altering routes explains how to do this.
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion