Drupal 8 is changing the way Drupal developers deliver content to the browser for a particular web page. It replaces parts of hook_menu() with Symphony2's HTTP Kernel. This approach is more object oriented and allows developers to decouple functionality which will make applications more flexible and maintainable.
The Drupal 7 way
Let's take a look at how we would define a route in Drupal 7. Lets say we want to add a new page to our site. In Drupal 7, we need to define an item in hook_menu(), that is an array, with the route as the array key, that defines certain things Drupal needs to know in order to figure out what content to send.
/**
* Implements hook_menu().
*/
function routing_example_menu() {
$items = array();
$items['routing_example/example_page/%/%'] = array(
'title' => 'My Example Page',
'page callback' => 'routing_example_example_page',
'page arguments' => array(2, 3),
'access callback' => 'routing_example_access_callback',
'access arguments' => array('authenticated user'),
'type' => MENU_NORMAL_ITEM,
'menu_name' => 'primary-links',
'weight' => -5,
'file' => 'routing_example.module',
);
return $items;
}
There are a lot of different things going on here: we are defining the function that will return the content; which arguments are passed to the function; where that function is located; who can see the content; what type of link it is; which menu the link shows in (if any); and, where in the menu it is displayed. That's a lot of information. It tightly couples together the route definition and the definition for the menu link, which are two different things. We could also not have included a menu link by making the type MENU_CALLBACK. So now you can have some items that are just routes, some items that are links, and some items that are both. Hook_menu() is trying to do too many things at once and it can get confusing.
The Drupal 8 way
Drupal 8 solves this problem by breaking out the route definition from the link definition. We now use one yaml file to define routes (module_name.routing.yml), and another to define menu links (module_name.menu_links.yml).
Routing Yaml File
The main parts of the routing yml file:
- module.route: machine name for the route
- path (required): is the URL for the route. This would have been your array key in Drupal 7
- defaults(required): defines how your content is delivered
- requirements (required): determines conditions that need to be set to allow access
- options (optional): additional options that will impact the route
routing_example.page:
path: 'routing_example/example_page/{name}/{title}'
defaults:
_content: '\Drupal\routing_example\Controller\ExampleController::examplePage'
custom_arg: 'custom'
requirements:
_role: 'authenticated user'
Here we've defined our path, and the function that will return. Drupal now uses PSR-4 convention so that your classes are automatically loaded when called. For your controller class to be discovered by Drupal it needs to live inside your module directory in:
[module_directory]/src/Controller/
and define its namespace as:
namepace Drupal\module_name\Controller
The Controller
Our controller code will look like this:
/**
* @file
* Contains \Drupal\routing_example\Controller\ExampleController.
*/
namespace Drupal\routing_example\Controller;
/**
* Example page controller.
*/
class ExampleController {
public function examplePage($custom_arg, $name = NULL, $title = NULL){
$build = array(
'#markup' => t("<p>Hello $name $title!</p><p>Custom argument is: $custom_arg</p>"),
);
return $build;
);
return $build;
}
}
The examplePage function in our ExampleController will be called when someone visits that URL, and will return our content to the browser. It will also receive three arguments: the custom arg we defined in the defaults, as well as the two arguments we defined in the route. Instead of the old wild card convention (%) in Drupal 7, Drupal 8 uses brackets{} with the argument name. In the requirements section we specify that the user must have the role 'authenticated user' to see this page. Drupal 8 allows you to provide or deny access based on roles, rather than having to define a custom function to restrict pages based on a role. You can find out more information about which options are available for your routing files here.
Drupal 8 was originally going to replace hook_menu() with another hook, hook_default_menu_links(), but the decision was made to move link definitions to yaml files as well. You can read more about that here: Providing module-defined menu links.
Summary
This is a quick introduction to Drupal 8's new routing system. We showed how Drupal 8 decouples different tasks that were all handled by hook_menu() in Drupal 7. For more information checkout the documentation page at drupal.org: https://drupal.org/developing/api/8/routing.