Event subscribers: A new hook system.

Published at

March 2, 2020

Author

Erlend ter Maat

Tags

Drupal, Drupal hook system


Last time I wrote about Drupal’s services mechnanism. Today I show what this technology has to offer for working OO in letting modules talk with each other: the hook system.

I was a little disappointed when I first saw Drupal 8. So many things were improved, but why did I still see this method-name-guessing mechanism of hooks? I did not follow. Until today. I guess this legacy code keeps following us a while. There is good news on this subject too. You are not forced to stick to this legacy method. I’m pleased to introduce to you it’s younger brother!

hook_menu_alter… (A Confession)

I was disappointed. That’s true. Actually I was disappointed because ‘they’ removed hook_menu_alter. Without asking me first! How could this happen? It happened to be one of the first hooks the Drupal code developers phased out.

From now on the things you did at hook_menu_alter are solved in this fashion:

# custom_module.services.yml
services:
  custom_module.routing
    class: Drupal\custom_module\Routing\CustomRouteSubscriber
    tags:
      - { name: 'event_subscriber' }
<?php

namespace Drupal\custom_module\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

class CustomRouteSubscriber extends RouteSubscriberBase {

  protected function alterRoutes(RouteCollection $routeCollection) {
    // Change route parameters in the collection object...
  }

}

Why is this better?

It looks ugly… I am used to drupal 3, 4, 5, 6, 7 style hooks. Maybe.

Module name clashes?

I often heard the complaint that the hook system forced one to create unique module names. But even though this is true; you should still give modules unique names. So this method is not better because now you can create another module with the same name.

Guessing the method name is not a method you should depend on - in itself. I value giving proper names to methods. A name should say something about what the method does. A method should do one thing as a means of writing maintainable code. And that one thing is briefly expressed in the method name. To let an outside system determine the name of the method forces me to give a name that probably does say anything about my purpose for the method. The new hook method allows developers to make the hook known to the origin of the hook by configuration, and gives more freedom to express what the customization is about in the names of classes and member variables and methods.

Explicit is better then implicit

I remember that I could get a little confused as I wrote custom drush commmands. I still can’t recall what the method name must be given a drush command key. Python has a saying “Explicit is better then implicit”. I think that’s true. The more specific you can be, the more predictable the output of your code will be. To specify the ‘hook’ in a yaml file makes your code more predictable.

It’s class based

The method based hook system persuaded developers to keep all code in one method. As a result the drupal hook implementation tended to look like spagheticode in a short time. It became hard to read and maintain. It brought developers to ideas of using switches and nested if statements.

Now you can dedicate one class to do one part of the customization. And if the customization gets to big, it’s easy to write 2 or more private methods that support your customization, all in the same file or module. It results in clean, maintainable code. This hook system allows you to write hooks in an object oriented fashion.

Order of execution

In some cases one would want to have a hook executed before or after all other hooks. A common solution for this is to change the order in which the modules are loaded by the drupal module system. I see a possibility to solve this in the yaml file. For example:

services:
  custom_module.routing
    class: Drupal\custom_module\Routing\CustomRouteSubscriber
    tags:
      - { name: 'event_subscriber' }
    weight: 100000000

However, in this solution I still have to guess a number high or low enough to have my hook be the last or first in execution order.

The order of execution is still something you don’t have a hand in as 3rd or 4th party module developer. I suggest another pattern to support this demand. If it applies to your custom hook that other developers may want edit the data in a specific place relative to other modules I suggest two patterns on how to implement this. It may be a state machine, where you provice parameters at the hook that indicate the context in which the hook is called. Or you provide a drag and drop GUI to have site administrators choose the order of execution. An example on the GUI for this can be found in the Examples for Developers modules at the ‘tabledrag_example’ module.

Conclusion

Event subscriber services do solve an important ‘problem’ of the former hook system in terms of OO and (therefore) readability, maintainability.

For further reading I refer to the drupal documentation, where hou can find an example on how you can create your own hooks in this fashion is found on drupal.org in the article “Subscribe to and dispatch events”.

Next time…

The most common way to access services is by means of depencency injection. Next blog post I will show how powerfull that is, and how this power can be used properly.