Drupal 8 is on the verge of its official release; according to the Drupal8Hivemind, there are just under 5 months to go! Regardless, the 8.x version is now in beta6, and the foundation is laid. It is now only about bug fixing; major changes to the APIs will no longer occur. This gives us a reason to communicate our familiarity with the (indeed significant) changes of the new version externally.
The aim of this article is to delve into the basics of module development for Drupal 8. We will develop a module that should produce a simple output on a path we have registered in Drupal. Later, we will integrate a service that displays Twitter feeds on our registered path.
Changes in the File System
The first significant change we notice is the heavily altered file structure of Drupal 8. All core files now reside in the "core" subfolder of the installation, thus being cleanly separated from the rest. Contrib modules, custom modules, etc., can then be installed directly in the "modules" subfolder. This also applies to themes, which can be placed accordingly in the "themes" subfolder. For multisite installations, the "sites" folder is still present. This makes the folder structure much more intuitive; especially Drupal newcomers will find it easier to navigate.
YAML Syntax Everywhere
We will therefore create our module (called "mymodule") in the "modules" subfolder. In contrast to Drupal 7, to enable the module, we only need a *.info file. The *.module file can also exist to contain the remaining hooks in Drupal 8, but it is now optional. The *.info file is the only one we need, and it should be written in Symfony’s YAML Syntax, so it also gets a ".yml" extension. In our case, "mymodule.info.yml". The content of the file is as follows:
name: MyModule
type: module
description: 'Drupal8 Module Sandbox'
package: Custom
core: 8.x
The only change from Drupal 7 is the "type" key with the value "module", which registers our extension as a module in the system. Similarly, themes would have the value "theme", for example. With this, we can already activate the module in our Drupal 8 backend by selecting it under the main menu "Manage -> Extend" and clicking save. Or with Drush "drush en mymodule".
Routing is Different
As a next step, we want to define the route where the output from our module will be displayed. In Drupal 7, we could achieve this with an implementation of hook_menu() in our *.module file. Drupal 8 has a separate system for routing, which is based on Symfony components. Essentially, you define the URL in a *.routing.yml file and assign it a controller that should be executed at that URL. The content of our mymodule.routing.yml file thus looks like this:
mymodule.hello_world:
path: '/mymodule/hello-world/{username}'
defaults:
_controller: '\Drupal\mymodule\Controller\HelloWorldController::feed'
_title: 'Hello World'
username: 'foo'
requirements:
_access: 'TRUE'
Our module can register multiple routes; therefore, the main key consists of the module and route names, separated by a dot. So, another route could also be registered, which could be called "mymodule.facebook_feed", for example. The "path" key specifies the URL; it also defines a placeholder for the username in curly brackets. The "defaults" array contains information about the path to the controller that should be called, the page title, which by the way is automatically registered by the translation system, and a default value for the username. The placeholder value is passed to our method as a variable; a default value can be set in the defaults array. In the "requirements" array, you can, for example, define permissions that make this page accessible (e.g. _permissions: 'access content'). For now, we are making it easy for ourselves and allowing everyone access to the URL.
Namespacing
A few words should also be said about the "_controller" key. The path to the controller is in the PSR-4 standard adopted by Drupal 8. Every module has a namespace corresponding to its module name; in our case, it is "Drupal\mymodule\". This namespace is assigned to the "src" folder in the root directory, i.e., "modules/mymodule/src/". This means that all additional folders after the module namespace are mapped identically in the file and folder structure of the "src" folder. For us, this means that "\Drupal\mymodule\Controller\HelloWorldController" implies that our controller should be in the file with the path "modules/mymodule/src/Controller/HelloWorldController.php". We create this file and add the following code:
namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;
class HelloWorldController extends ControllerBase {
public function feed($username) { $content = array( '#markup' => t('Hello ' . $username), );
return $content;
} }
First, we define the namespace in which our controller resides. Then, we create our "HelloWorldController" class, which extends the "ControllerBase" class and references the virtual path to this class (with "use Drupal\Core\Controller\ControllerBase;"). Our controller initially contains only a very simple "feed" method, which receives the username part in the URL as a variable. For this simple example, we could certainly define a simple class that does not extend ControllerBase. However, the reason we do this is that via "ControllerBase" we automatically get utilities available in our controller (e.g. the t() function), which we would otherwise have to bring in ourselves if needed. More information about the ControllerBase class can be found on api.drupal.org.
To register the changes in our code in the system, we still need to clear the cache (in Drupal 8 under "admin/config/development/performance" or with Drush "drush cr"). After that, the output of the feed method should be displayed on the registered path ("mymodule/hello-world" or "mymodule/hello-world/bar"). And with that, you have completed the first milestone in Drupal 8 development.
In the next blog post in the series, we will go a step further and then address the concept of Services and Dependency Injection with our module to implement a service that will then also display Twitter feeds on our defined URL.
Conclusion
If you have installed Drupal 8 and take a look at the new Bartik theme, you will not yet realise how many changes the system contains. It becomes clear how much work has gone into the new version at the latest when you start to deal with the code. At first, it is certainly a little overwhelming, but familiarity with the object-oriented world quickly becomes enjoyable because the new concepts are mature and future-proof. Importantly, the fundamental software structure is maintained; the approach is different.

