One of the Aspects of Drupal 8 that seemingly has confused people a great deal, but upon closer inspection is not exceptionally difficult to understand, is the routing system. While the system has a foreign sounding name compared to systems you might be familiar with in older Drupal versions, the underlying functionality the routing system controls will actually seem quite familiar once you take a look at the code and what it does.

Essentially, the routing system in Drupal 8 is leveraged from Symfony and largely replaces the path and page callback components of hook_menu() from Drupal 7. This refers to how Drupal registers or defines a path (or now route) for which content is rendered. The differences in how this code is laid out in Drupal 8 might seem strikingly different, object-oriented classes and YAML files, but the spirit of the end-result and what it is accomplishing should feel very similar.

One of the most common use cases of this functionality which you might have worked with in Drupal 7 would be hook_menu_alter() or the modification of existing menu paths, possibly to change access or the callback for the page’s rendered content.

In Drupal 8, the RouteSubscriberBase class is extended in your custom code to register routes that you wish to alter, from a list or “collection” of all built routes. The following code snippets are examples of how you can work with this class to modify access or the content on various existing pages.

The examples contain two different components in order to function as part of your custom module. First, is the custom subscriber class file, which might be named and placed in your custom module like so: “/src/Routing/RouteSubscriber.php”. Secondly would be the registering of your subscriber class within the configuration of the module, in a YAML file named and placed like this: “/example.services.yml”.

Examples of a custom RouteSubscriber:

(from Drupal.org)

The following example modifies two routes from the User module, one changes the URL which will take you to the user login page, while the second places a permanent denial of access to the user logout page. (/src/Routing/RouteSubscriber.php)


namespace Drupal\example\Routing;
 
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
 
/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {
 
  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    // Change path '/user/login' to '/login'.
    if ($route = $collection->get('user.login')) {
      $route->setPath('/login');
    }
    // Always deny access to '/user/logout'.
    // Note that the second parameter of setRequirement() is a string.
    if ($route = $collection->get('user.logout')) {
      $route->setRequirement('_access', 'FALSE');
    }
  }
 
}

The services registration for this class would look as such (/example.services.yml):


services:
  example.route_subscriber:
    class: Drupal\example\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }

(from drupal.stackexchange.com) The following example would remove a route from the collection, perhaps a page or form you no longer want to have shown.


class RouteSubscriber extends RouteSubscriberBase {
 
  /**
   * {@inheritdoc}
   */
public function alterRoutes(RouteCollection $collection) { 
  // Remove the /search route. 
  $collection->remove('search.view'); 
}
 
}

You can also register specific keys or callbacks that can be checked for in a separate class for UserAccess and AccessCheckInterface, so that you can add some custom access control functionality and behavior. (We’ll touch on those features in a later blog post.) The final example here sets a requirement for a custom access check key to be true on the user edit form. And this custom access check key will be evaluated for in a custom UserAccess class as mentioned above.


class RouteSubscriber extends RouteSubscriberBase {
 
  /**
   * {@inheritdoc}
   */
public function alterRoutes(RouteCollection $collection) {
    $route = $collection->get('entity.user.edit_form');
    $route->setRequirement('_user_form_user_access', 'TRUE');
  }
 
}

So as you can see, the routing system in Drupal 8 certainly does the things you will be familiar with from Drupal 7, though the code involved is quite different and somewhat more substantial in length. The upside to this change though is that it leverages work put into Symfony and will be easier to maintain, and as well the wide variety of functions that hook_menu() handled have been broken out and made more distinct.