Anatomy of a Drupal 8 Module: Part 1. Overview.

The best way to get to know a technology closer is to study it's code. Drupal 8 is a huge step forward technologically from Drupal 7, and it has literally tons of code that I feel I need to review and learn from. And I welcome comments and crtiticism from the readers.

The module that I chose to start with is a simple one: the Ban module. It's used to ban IPs via interface and first appeared in Drupal 7, undergoing a rewrite for Drupal 8. Why I chose this module? Because it's simple. We'll take the Drupal 8 module as an example and lay out it's anatomy and of how a Drupal 8 module is built, and try to explain some new concepts with it.

This is the first part of the article. There is also Part 2, dealing with code and some OOP concepts.

And, you can always get Drupal 8 from drupal.org and see the code yourself, and play with it. So, here we go.

1. Info File.

Info files have long been used in Drupal to identify themes and modules. Until Drupal 8, there has been a single .info file, that defined the name and machine name of the module, it's description, dependencies, and attached js and css assets. This is pretty much the same in Drupal 8, except that the info file is now a part of the the wider Drupal 8 Configuration Management System. So, the info file is actually named ban.info.yml.

ban.info.yml

type: module
description: 'Enables banning of IP addresses.'
package: Core
version: VERSION
core: 8.x
configure: ban.admin_page

2. Other Config Files.

In Drupal 8, configuration is stored in YAML files in YAML format. It originates in themes and modules folders, and is then copied over to a compiled config folder that Drupal then uses. Config can then be imported and exported via UI. And, config elements are entities.

What do BanIP's config entities store?

File Config
ban.info.yml A module's info file.
ban.links.menu.yml Definitions for admin pages.
ban.permissions.yml Permissions that this module introduces.
ban.routing.yml Menu link definitions, replacing hook_menu(). Paths are mapped to handling classes.
ban.services.yml Drupal services classes and their initial configuration.

3. Install File.

The purpose of ban.install file is to run code during the module installation and un-installation. In this case, the Ban module defines it's schema via the hook_schema() hook. This will install the ban_ip table into the database and create it's fields when Ban module is installed, and delete the table when it's uninstalled. There is no 'disabling' in Drupal 8 like it used to be in previous versions.

4. Module File.

The main module file's naming convention as been preserved. ban.module if the main module file. In our case, however, because he main functionality has been routed though the YAML files and mapped to classes, this main module file only contains the hooks, namely, hook_help(), that will be displayed in Drupal's help interface when help about the Ban module is requested.

5. src Folder.

The src folder contains the classes that are the actual sources for the Ban module.

6. src/Form Folder.

Ban module has two forms. Each form is encapsulated in a class and placed in the src/Form folder. BanAdmin.php and BanDelete.php are the two forms that are used in the Ban module. How does Drupal 8 know when to call these forms? They are both declared in the ban.routing.yml file.

7. src/Tests Folder.

The src/Tests foler contains a class, that submits the Ban module's functionality to the Drupal's built-in testing engine.

8. src/BanIPManagerInterface.php File.

The BanIPManagerInterface.php file provides an interface for the BanIPManager class. By providing an interface, developers create possibility for other classes that implement that interface, to be created. Interface is like a blueprint for a class, it lists the functions that classes that implement it, must posess.

9. src/BanIPManager.php File.

The BanIPManager.php file contains a class, that implements the BanIPManagerInterface. In other words, this manager class is built according to it's interface blueprint. It implements the actual functionality of managing the banned and un-banned IPs.

How does Drupal 8 know when to use the BanIPManager class? It is declared in the ban.services.yml file.

10. src/BanMiddleware.php File.

In Drupal 8, a middleware is usually a subclass of the core. The BanMiddleware.php file contains a class, that subclasses the Drupal's core to achieve it's purpose. Core is not frequently subclassed in Drupal 8, since core sublassing is a low-level change that works on such drastic levels, that are usually unneeded for the most modules. However, in our case, Ban module prevents normal Drupal core's work if the HTTP request comes from a banner URL, and so, it needs to subclass the core itself.

How does Drupal 8 know when to use the BanMiddleware class? It is declared in the ban.services.yml file.

11. tests/src/Unit/BanMiddlewareTest.php file.

Why Unit/BanMiddlewareTest.php class is not in the src/Tests folder, where are tests are located?

This is an interesting question. A simple answer is this. The kernel subclass will be tested with a different testing engine - PHPUnit. While the usual Drupal tests require a complete Drupal bootstrap, Unit testing can be ran on the pieces of code that are decoupled enough - such as Drupal's Kernel and it's subclass.

Conclusion.

If you build a Drupal 8 module, you would most probably do something very similar - you would declare the info file data, routing configs and forms in the corresponding YAML files, hooks in the main module file, and the classes that the config maps to in the source files in the src folder.

In the next part, we will look close at the code - at YAML, and the concepts of services, subclassing, autoloading, and the dependency injection.