Drupal 9 Module Development - Third Edition

3 (2 reviews total)
By Daniel Sipos
    Advance your knowledge in tech with a Packt subscription

  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Chapter 1: Developing for Drupal 9

About this book

With its latest release, Drupal 9, the popular open source CMS platform has been updated with new functionalities for building complex Drupal apps with ease. This third edition of the Drupal Module Development guide covers these new Drupal features, helping you to stay on top of code deprecations and the changing architecture with every release.

The book starts by introducing you to the Drupal 9 architecture and its subsystems before showing you how to create your first module with basic functionality. You’ll explore the Drupal logging and mailing systems, learn how to output data using the theme layer, and work with menus and links programmatically. Once you’ve understood the different kinds of data storage, this Drupal guide will demonstrate how to create custom entities and field types and leverage the Database API for lower-level database queries. You’ll also learn how to introduce JavaScript into your module, work with various file systems, and ensure that your code works on multilingual sites. Finally, you’ll work with Views, create automated tests for your functionality, and write secure code.

By the end of the book, you’ll have learned how to develop custom modules that can provide solutions to complex business problems, and who knows, maybe you’ll even contribute to the Drupal community!

Publication date:
August 2020


Chapter 1: Developing for Drupal 9

Drupal is a web-based Content Management System (CMS). While it is useful out of the box, it is designed with developers in mind. The purpose of this book is to explain how Drupal can be extended in many ways and for many purposes. To this end, the version we will use will be the latest one at the time of writing this book—Drupal 9.

In this book, we will cover a wide range of development topics. We'll discuss how to create a Drupal 9 module, and as we go through the chapters, we'll cover many concepts and tips that will help you build what you need. The goal is not only to explain how things work but also to go through some examples in order to demonstrate them. Since no book can contain everything, I hope that after reading this book, you'll be able to expand on your knowledge on your own using the resources I reference and by looking into the Drupal core code itself. As helpful as such a book can be for learning any kind of software development, if you really want to progress, you will need to apply the knowledge you learned and explore the source code yourself. Only by doing this will you be able to understand complex systems with many dependencies and layers.

This chapter introduces the terminology, tools, and processes for developing modules in Drupal 9. While subsequent chapters focus on code, this chapter focuses on concepts. We'll talk about the architecture of Drupal and how you can hook into Drupal at strategic places to extend it to accomplish new tasks.

The following are the major topics we will be covering in this chapter:

  • An introduction to Drupal development
  • How did we get to Drupal 9?
  • Drupal 9 architecture
  • The major subsystems of Drupal
  • Tools for developing in Drupal

By the end of this chapter, you will understand the architectural aspects of Drupal and be ready to start writing code.


Introducing Drupal (for developers)

Out of the box, Drupal traditionally has all the standard functions of a web-based content management system:

  • Visitors can view published information on the site, navigate through menus, view listings, and individual pages, and so on.
  • Users can create accounts and leave comments.
  • Administrators can manage the site configuration and control the permissions of users.
  • Editors can create, preview, and then publish content when it is ready.
  • Content can be syndicated to RSS, where feed readers can pick up new articles as they are published.
  • With several built-in themes, even the look and feel of the site can be easily changed.

However, Drupal 8 improved on these and introduced some more powerful capabilities. For example, advanced multilingual support, content moderation, layout building, REST API, and many other features are now available out of the box. And yes, I did mean Drupal 8 because all this started with that version and is continuing with the current Drupal 9.


How did we get to Drupal 9?

Drupal 9 does not represent a great milestone in the traditional sense. It does, but not one comparable in scale to the release of Drupal 8.0 when the entire world cheered and the stock markets rallied. Rather, Drupal 9 represents proof that some decisions were made wisely when the time came to change the release approach Drupal was accustomed to.

Before Drupal 8, every few years a major version of Drupal was released. And with these releases came the joy of getting all the new features and leaving the old behind. But what also came was the pain of upgrading to these new releases. No more, said Drupal 8, which has been steadily introducing new features and functionality with each minor release until now. To the point that we have reached the end of the Drupal 8 release cycle and have gone into Drupal 9 in almost the same way as we've been going from one minor release to another, say, from 8.5 to 8.6. But then what is the difference?

In semantic versioning, minor releases mean that new features can be added as long as backward compatibility is ensured on all existing APIs. This means that even if in 8.5 you realize a public API is stupid and want to change it, you must ensure that in 8.6 it remains functioning. In a deprecated state, sure, but still compatible. Most of the time, these APIs simply delegate to the new, shiny ones. But as time goes on, the codebase gets full of this deprecated code that should not be used anymore. Enter major releases, such as Drupal 9.

Major releases allow the removal of all the deprecated code and instruct developers and users of the software to ensure that they are compatible with all the new APIs and that they ditch the old ones. So, this is exactly what Drupal 9 is doing: removing all the deprecated code from 8.9 and calling it Drupal 9. The two will be identical in many respects.

Why now, though? Why not in 4 years? Or 5? Apart from the growing codebase full of useless code and the increasing difficulty of managing these deprecations, Drupal is also facing the challenge of maintaining its dependencies. Ever since it "got off the island" and started relying on other open source libraries, it also got dependent on their life cycles. Here, the most notable is Symfony. Drupal 8 has been using Symfony 3, whose end of life is set for November 2021, and therefore the end of life of Drupal 8 needs to coincide with that. Upgrading to Symfony 4 would mean breaking backward compatibility, so a new major version of Drupal is also needed. Besides, there are plenty of libraries that stand to be updated as well, such as Twig to version 2. Which is also great.

Where does this leave our book? Everything you will learn in this book will be compatible with Drupal 9. Many of the things will also be compatible with Drupal 8, especially later versions of it, and with slight adjustments. For this reason, going forward, I will refrain from mentioning specific versions of Drupal because it makes less and less sense to do so. Except, of course, when it becomes germane to my point to be specific about the version.


Developing for Drupal

As fantastic as these features are, they will certainly not satisfy the needs of all users. To that end, Drupal's capabilities can be easily extended with modules, themes, and installation profiles. Take a look at Drupal's main website, http://drupal.org, and you will find thousands of modules that provide new features and thousands of themes that transform the look and feel of the application or website.

The flexible way Drupal can be extended and transformed through the module and theme mechanisms has led many to claim that Drupal isn't just a CMS, but a Content Management Framework (CMF), capable of being re-tooled to specific needs and functional requirements.

Establishing whether Drupal is rightly called a CMS or CMF is beyond our purpose here, but it is certain that Drupal's most tremendous asset is its extensibility. Want to use a directory server for authentication? There's a Drupal module for that. Want to export data to Comma-Separated Value (CSV) files? There are several modules for that (depending on what data you want to export). Interested in Facebook support, integration with Twitter, or adding a Share This button? Yup, there are modules for those too—all of which are available on Drupal.org and provided by developers like you.

Want to integrate Drupal with that custom tool you wrote to solve your special business needs? There may not be a module for that, but with a little bit of code, you can write your own. In fact, that is the subject of this book—providing you with the knowledge and tools to achieve your own goals.

In summary, the purpose of this book is to get you ramped up (as quickly as possible) for Drupal 9 module development. As we move chapter by chapter, we will cover the APIs and tools that you will use to build custom Drupal sites, and we won't stick to theory. Most chapters provide working, practically oriented example code designed to show you how to implement the concepts we will be talking about. We will follow Drupal coding conventions and utilize Drupal design patterns in an effort to illustrate the correct way to write code within the Drupal development context.

While I certainly can't write the exact code to meet your needs, my hope is that the code mentioned in these chapters can serve as a foundation for your bigger and better applications.

So let's get started with a few preliminary matters to better understand Drupal.


Technologies that drive Drupal

Drupal has gone through a series of different best practices for when it comes to how it should be installed. But the reality is that they are simply tailored to different needs. The most common, and the most recommended by this author, is the Composer-based approach with the Drupal community-promoted project here: https://www.drupal.org/docs/develop/using-composer/starting-a-site-using-drupal-composer-project-templates.

You can read more about how to install Drupal there, so I will not go into details here. Instead, let's talk a bit about the technologies that power (or are needed by) Drupal 9.


Drupal is written in the PHP programming language. PHP is a widely supported, multiplatform, and web-centric scripting language. Since Drupal is written in PHP, this book will largely feature code written in PHP, albeit with Drupal standard practices being kept in mind.

It is very important to note that the minimum version of PHP required for Drupal 9 to run (and install via Composer) is 7.3. Therefore, PHP 7.1 is no longer supported as it reached its end of life in December 2019.

Databases and MySQL

Drupal uses the powerful PHP Data Objects (PDO) library that is standard in PHP 7. This library is an abstraction layer that allows developers to support numerous databases, including MySQL, PostgreSQL, SQLite, and MariaDB.

The minimum database versions for Drupal 9 are as follows:

  • MySQL 5.7.8/MariaDB 10.3.7/Percona Server 5.7.8 or higher with PDO and an InnoDB-compatible primary storage engine
  • PostgreSQL 10 or higher
  • SQLite 3.26 or higher

The web server

Apache has long been the predominant web server, but it is by no means the only server. While Drupal was originally written with Apache in mind, many other web servers (including IIS, Lighttpd, and Nginx) can run Drupal.

We do not explicitly cover the web server layer anywhere in this book, primarily because development rarely requires working at that low level. However, Drupal expects a fair amount of processing from the web server layer, including the handling of URL rewriting.

The two most common web servers you'll typically run Drupal on are Apache and Nginx, with the following minimum version requirements for Drupal 9:

  • Apache 2.4.7 or higher
  • Nginx 1.1 or higher

HTML, CSS, and JavaScript

The de facto web data format is HTML styled with Cascading Style Sheets (CSS). Client-side interactive components are scripted with JavaScript. As Drupal developers, we will encounter all three of these technologies in this book. Although you don't need to be a JavaScript ninja to understand the code here, you will get the most from this book if you are comfortable with these three technologies.

Drupal architecture

In the previous section, we introduced the technologies that drive Drupal. However, how do they all fit together? How is the code organized? In this section, let me give you a quick overview of this architecture.

Drupal core, modules, and themes

From an architectural standpoint, we can break up Drupal into three pieces: its core, modules and themes.

When we discuss Drupal core, we can interpret it in two ways. A more restrictive interpretation sees it as the functionality covered by all the code it ships with, excluding modules and themes. The more widespread interpretation sees it as the total codebase it ships with (out of the box).

Although the most widespread interpretation is the latter (not least because it differentiates all the functionalities its standard installation contains versus all others provided by contributed modules and themes), it is interesting to consider the first one as well, even if just for a minute. Because in doing so, we can distinguish, architecturally speaking, the base code from the modules and themes that provide various functionalities and layouts. And why is this distinction interesting? Because at the bridge between the two come into play the hooks and events that will also allow us to inject ties to our own functionality.

The core libraries are made up of code belonging to the Drupal project and those from the wider PHP community, which Drupal borrows under open source licensing. This latter approach was new in Drupal 8, continued in Drupal 9, and has been regarded by many as a positive shift toward getting off the Drupal island and embracing outside libraries, frameworks, and communities.

Essentially, the core libraries provide the functions and services used throughout Drupal. For example, helpers for interacting with the database, translating between languages, sanitizing user data, building forms, encoding data, and many such utilities are found in Drupal's core libraries.

The modules (both core and contributed) are where most of the actual business logic is encapsulated. If enabled, they can provide functionality or extend the existing one. Most of the core modules are needed and cannot be disabled due to their importance in the standard Drupal installation. However, contributed ones can be installed and uninstalled as needed.

The themes (both core and contributed) are an important part of the theme system and are used by the presentation layer. They provide HTML templates within which content and data can be rendered to the user, as well as CSS styling and even client-side scripting for some nice visual interactions. Themes can extend other themes and can also contain some PHP logic to process the data before being rendered.

Now that we have seen what the core libraries, modules, and themes do, let's talk briefly about hooks and events to understand how they are all connected.

Hooks, plugins, and events

Hooks are a very typical Drupal procedural concept that allows Drupal core and modules to gather data from other modules and themes (or expose it). By doing this, the latter can provide new functionality or alter existing ones. It is the responsibility of the code that invokes the hook to make use of whatever the hook implementations return. The format for whatever the latter needs to return is usually described in the hook documentation.

Concretely, hooks work by scanning installed modules and themes, and looking for a function that follows a specific naming pattern (in other words, a hook implementation). This is, in most cases, in the following format—module_name_hook_name. Additionally, there are also alter hooks, which have the word alter tacked on the end of the function name and are used to change data passed as a reference to the hook implementation. We will see examples of hooks later in the book.


Developers with a background in Object Oriented Programming (OOP) or with a strong knowledge of design patterns might recognize this as being similar to the event handling paradigm captured in the Passive Observer pattern. When some particular event occurs, Drupal allows modules the opportunity to respond to that event.

In previous versions of Drupal, up until Drupal 8, hooks were KING. Yes, I wrote this in capital letters; my Caps Lock did not get stuck. This is because they were the way to add or extend functionality in modules. As such, they were the single most important aspect of Drupal programming. In Drupal 8, however, although still important, they took a backseat to new concepts, such as plugins and events. There is talk of having them removed completely in Drupal 10 or 11. Let's see.

Since Drupal 8, I dare to say that plugins are king. Much of the logic that used to be tied to Drupal via hooks is now added in through plugins (not to be confused with WordPress plugins). Drupal plugins are discoverable bits of the functionality centralized by a manager and that are used for certain tasks and features. We will see more about plugins and provide many examples later in the book.

A third extension point introduced in Drupal 8 is the event system. Unlike the first two, however, this is not specific to Drupal, but is, in fact, the actual Symfony EventDispatcher component (http://symfony.com/doc/current/components/event_dispatcher.html). Events are primarily used in Drupal to intercept certain actions or flows in order to either stop or modify them. Many request-to-response tasks that were handled via hooks in the past are now being handled by dispatching events to check whether any modules are interested in, for example, delivering the response to the user.

Services and the dependency injection container

Another architecturally important element of Drupal is the Symfony dependency injection component (http://symfony.com/doc/current/components/dependency_injection.html), specifically represented by the service container.

This component is a staple of modern OOP PHP programming and as such has become foundational to Drupal since version 8. It allows us to create services that can be injected in various places of our code in order to handle certain functional (and often swappable) tasks. Additionally, they can also be used as an extension point because the service container is able to group services that have very specific responsibilities and use them for a purpose automatically. In other words, simply by defining a simple service, we can provide our own functionality or even change existing logic.

We will encounter many services, and we will see how we can declare our own later in this book.

From request to response

Now that we have listed the most important architectural pieces of Drupal, let's briefly see how these are used in delivering responses to the requests a user makes on a Drupal website. To this end, we will analyze a simplified example of a handled request:

  1. A user accesses the http://example.com/node/123 URL in a web browser.
  2. The browser contacts the web server at example.com and requests the resource at /node/123.
  3. The web server recognizes that the request must be handled by PHP and starts up (or contacts) a PHP environment to handle the request.
  4. PHP executes Drupal's front controller file (index.php), which then creates a new Request object from the resource that was requested.
  5. Symfony's HTTPKernel handles this request object by dispatching a number of events, such as kernel.request, kernel.controller, kernel.response, and kernel.view.
  6. The route that maps to that request is identified through the kernel.request event.
  7. The route controller is identified, and the kernel.controller event is used to perform any alterations on the responsible controller, as well as to resolve the arguments that need to be passed to it. In our case, this route is registered by the Node module through the main Entity system, which identifies the entity ID, loads it, and builds the markup to be returned as part of the response.
  8. If the respective controller (or handler) returns something other than a response object, the kernel.view event is dispatched to check whether there is any code that can transform that into a response object. In most cases, controllers typically return render arrays, which are transformed into response objects.
  9. Once a response is created, the front controller returns it to the browser and terminates the request.

In this context, as module developers, we spend most of our time inside controllers and services trying to figure out what we need to return to the page. We then rely on Drupal to transform our render array into a proper response to the user, but we can also return one ourselves directly. Moreover, the theme system comes into play here, as well as the block system, because our content gets wrapped into a block that is placed in a region surrounded by other regions that contain other blocks. If it sounds complicated now, don't worry; we will cover in detail all these aspects with examples, and it will become clear in no time.

Drupal's major subsystems

In the previous section, we took a brief look at Drupal's architecture. Now we will refine our perspective a bit. We will walk through the major subsystems that Drupal has to offer.


It all starts with a route, doesn't it? Most interactions with a Drupal website begin with a user (or system) accessing a certain path (or resource). This translates into a route, which maps that resource to a flow that (hopefully) returns a successful response back, or at least a graceful failure.

The routing system is a major shift away from how it used to be in versions before 8. In Drupal 7 and before, the routing system was a very Drupal-specific thing (a drupalism, if you will). Many of us remember hook_menu as a staple hook each Drupal developer had to know very well. All of that has been abandoned since Drupal 8 in favor of the Symfony Routing component (http://symfony.com/doc/current/components/routing.html). Also, since I mentioned hook_menu, I will also mention that its other main functions have also been taken over by other subsystems, such as plugins.

In Chapter 2, Creating Your First Module, we will see how we can define our own route and map it to a controller that will render our page. We will cover a few of the more important route options and take a look at how we can control access to these routes.


Progressively, entities have become a very powerful way of modeling data and content in Drupal. The most famous type of entity has always been the Node, and it has been historically the cornerstone of content storage and display. Since Drupal 8, the entire entity system has been revamped to make any other entity types potentially just as important. They have been brought to the forefront and have been properly connected with other systems.

All entity types can have multiple bundles, which are different variations of the same entity type and can have different fields on them (while sharing some base fields).

Drupal core still ships with the Node entity type, with a few bundles such as Basic Page and Article in its standard installation profile. In addition, it comes with a few other entity types, such as User, Comment, File, and so on. And creating your own entity type has become much more standardized compared to Drupal 7, for example.

These are not the only types of entities we have, though. The aforementioned examples are all content entity types. Drupal 8, however, also introduced the configuration entity types. The former are for modeling content, but in reality, they are for anything that holds data that can be stored in the database and is specific to that environment. They are not used for storing configuration, though. Users and content are great examples, as they do not need to be (usually) deployable from one environment to another. The latter, on the other hand, are exportable items of configuration, of which there can be more than one. For example, a content entity bundle is a great example because there can be more than one bundle for a certain content entity type; they have some metadata and information stored that can differ from bundle to bundle, and they need to be deployed on all environments. That is, they are fundamental to the correct functioning of the site.

Understanding the entity system is indispensable for doing development in Drupal because it provides a powerful way to model custom data and content.

Now that we have an idea of what entities are, let's take a look at how data is actually stored on these entities.


I have alluded in the previous section to how certain entity bundles can have various fields. This means that each entity type bundle can have any number of fields that are responsible for holding data. Additionally, each entity type itself can have fields for storing data. Okay, but what? Let's break this down.

There are two types of fields in Drupal—base fields and configurable fields. The former are fields that are defined in code for each entity type, whereas the latter are usually created and configured in the UI and attached to a bundle of that entity type (and exported via configuration).

Fields can also be of multiples types, depending on the data they store. You can have string (or text) fields, numeric fields, date fields, email fields, and so on. As developers, we can create our own field types if the existing ones are not good enough for our data.

In this book, we will take a look at how we can define base fields on a certain entity type and create our own field type with its own data input widget and output formatter. Site builders can then use this field type on any entity type.


Any site needs some sort of navigation, right? Drupal not only maintains content, but also provides details about how the site itself is organized. That is, it keeps a structure of how content is related.

The principal way that it does this is through the menu subsystem. This provides APIs to generate, retrieve, and modify elements that describe the site structure. Put in common parlance, it handles the system's navigational menus.

Menus are hierarchical; that is, they have a tree-like structure. A menu item can have multiple children, each of which may have their own children, and so on. In this way, we can use the menu system to structure our site into sections and subsections.

In this book, we will see how we can work programmatically with menus and menu links.


Listing content and data is always an important capability that CMSes covet; and this is what Views does in Drupal. And it does it well.

The purpose of the Views module is to expose data and content in a way that allows the creation of configurable listings. It includes things such as filters, sorts, display options, and many other features. As developers, we often find a need to write our own field or filter plugin to work with Views or expose data from our custom entities or external data sources.

Views is tied to the general architecture and used for most list pages (especially admin pages) provided by Drupal core. Although it's a very site building-oriented tool, in this book, we will take a look at how we can create plugins that extend its capabilities to offer site builders even more.


Unless your site has three pages and five paragraphs of text, the likelihood that you will need to capture user input via some type of form is very high. Also, if you've been coding PHP applications you know how forms have always been a pain from the point of view of securely and efficiently rendering and processing the submitted data. As soon as you use a PHP framework such as Symfony or Laravel, you will note that an API is in place to take much of that load off your shoulders.

The same goes with Drupal and its powerful Form API. Historically, it has been a great abstraction over having to output your own form elements and deal with posted values. It allows you to define your own form definition in OOP and handle validation and submission in a logical way. Its rendering and processing are taken care of by Drupal securely, so you don't have to worry about any of that.

In this book, we will encounter some forms and see how they actually work in practice.


One of the major pet-peeves of Drupal developers (and developers of other popular CMSes for that matter) has always been the way configuration is handled and deployed from one environment to the next. Drupal 7 stored most of its configuration in the database, so various solutions had to be concocted by developers to get that moved up the ladder as development progressed.

Since Drupal 8, great advancements have been made in this respect with the introduction of a centralized configuration system. Although it stores all configuration in the database, it allows it all to be exported into YAML files (and then reimported). So, from a development point of view, we have a much better experience if certain features depend on configuration (for example, a new field). This system is continuously being improved with powerful milestones being reached in the latter versions of Drupal 8.

Configuration is also of two kinds—simple and complex (configuration entities we noted in the Entities section). The difference between the two is that simple configuration is always singular. In other words, there is only one instance of itself. For example, the site name and email address are stored inside such a configuration item. You wouldn't expect the need for more than one instance of these two value items. However, in the case of the complex configuration, you would. For example, a View definition is such a configuration entity because it follows a certain schema and we can have multiple View definitions. Makes sense, doesn't it?


Plugins are an elegant solution to an important problem— encapsulating functionality. Right off the bat, you should not confuse them with things such as WordPress plugins, which are more akin to Drupal modules. Instead, you should think of plugins as components of reusable code that can be used and managed by a central system. Typically, they are used when a system handles a task in a certain way (plugin A) but allows other modules to provide different ways to handle that task (plugin B or C).

You can also look at plugins as being opposite to entities: not used for data storage, but for functionality. Instead of creating a type of data that gets stored, you create a type of functionality that is used. The two usually work hand in hand, especially when it comes to manipulating data in different ways.

An important aspect of how they work is their discoverability. Most plugin types are discovered via something called Annotations. Annotations are a form of DocBlock comments, borrowed from the Doctrine library (http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html), by which we can describe classes, methods, and even properties with certain metadata. This metadata is then read to determine what that item is without the need for instantiating the class. In Drupal, we use annotations only at a class level to denote that it is a plugin implementation with certain characteristics.

The second most common discoverability method for plugins is via a YAML file, and a popular example of those are menu links (as we will see later in the book). However, for now, you should know that plugins are very widely used, and we will create quite a few plugins in this book.

The theme system

The responsibility for theming a given piece of data is spread out over Drupal core, modules, and the themes themselves. So, as a module developer, it is important to know that both modules and themes can theme data or content.

In this book, we will focus on the aspects that happen at the module level. We will not concern ourselves with styling, but instead we will work primarily with theming definitions and templates that are needed within the module. Typically, it is best practice to ensure that modules are able to theme their data. If done right, themes can then come into play to style the output or override that theming to change the presentation altogether.

A major shift in Drupal 8 compared to older versions is the move to the open source Twig templating system (https://twig.sensiolabs.org/). This makes the separation of logic from a presentation that much clearer and makes frontend developers, jobs much easier, not to mention more secure. And with Drupal 9, the version of Twig has been finally upgraded from 1 to 2.


The last major subsystem that I will include here is the caching layer. Since version 8, Drupal has gone to great lengths to improve the performance of building pages and rendering data. To this end, the caching system has become an important part to consider whenever we either do complex or heavy calculations or render content.

From a module developer's perspective, there are two main pillars of the caching system. The first one provides developers with a cache backend to store the results of complex data calculations. This can be read in the next requests to avoid the need for reprocessing that task. This goes hand in hand with the cache invalidation that happens when something in the system changes that would require the calculations to be redone. The second pillar is the render cache, which allows developers to wrap their output with metadata that describes when the cache of that output needs to be invalidated.

We will see these in action in a later chapter dedicated to caching.

Other subsystems

There are other subsystems in Drupal 9 of varying importance. I chose to include the previous ones because I deemed them to be the most important to be introduced up front and especially from the point of view of a module developer. However, as we progress through the book, we will definitely encounter others.

Tools for developing in Drupal

Drupal is a sophisticated platform, and from the glimpse provided in this chapter, we can already see that there are numerous systems and structures to keep track of. In this section, I will mention a few tools that simplify or streamline the development process.

Going forward, I assume that you have your own web server stack and your own PHP development tools. However, if you are just getting started, you may want to look at Acquia Dev Desktop from Acquia (http://acquia.com). It offers entire application stacks to get you started on Windows, Linux, or macOS. Alternatively, if you are even just a bit more advanced, you can consider the Drupal VM (https://www.drupalvm.com/), a Vagrant and Ansible-based local development environment ready for Drupal.

Finally, the most flexible development environment, in my opinion, is the Docker-based one. You can easily get started with a pre-made and well-documented stack here: https://github.com/wodby/docker4drupal. All the code we write in this book can be found in the GitHub repository referenced in the introductory pages. However, a quick-to-set-up Docker-based environment is also provided there. So, with just a few commands, you can have a Drupal 9 site up and running, and you can test the code of each individual chapter with ease. Do make sure you check it out and try using it. Simply follow the instructions in the repository README file.

As for a code editor, I personally use PhpStorm (as many others do), but you are free to use whatever IDE you want because Drupal itself doesn't require anything special. Do, however, use some sort of an IDE because it will make your life much easier.

Additionally, while running a PHP debugger is certainly not necessary, you may find running Xdebug or the Zend Debugger to be useful. I personally recommend a PHP debugger wholeheartedly, not only for debugging itself, but also for understanding the processes that happen under the hood.

Version control

Any software development needs to happen through a version-controlled environment. By now, Drupal is universally using Git. So, you should make sure that you have Git installed locally, even if just to be able to check out the code examples we write in this book, which are hosted on GitHub.


As I alluded to earlier, installing Drupal is best done via the Composer recommended project. However, you may also install it straight from Git by checking out the latest tag or commit in the Drupal.org Git repository (https://www.drupal.org/project/drupal/git-instructions). If you do this, you will need to install its dependencies via Composer, and Drupal has many.

To this end, you will need to have Composer available on your development environment and have a basic understanding of how to use it.

The API site and coding standards

A lot of background knowledge is required for writing good Drupal code. Of course, the aim of a book such as this is to try to provide as much of that background knowledge as possible. However, self-documentation and research still remain key, and there are a number of resources that a Drupal developer should have on-hand.

The first is the official online API documentation. Just about every function in Drupal is documented using inline code documentation. The Doxygen program is then used to extract that documentation and format it. You can access the full API documentation online at http://api.drupal.org.

Along with using the Drupal APIs, we strive to comply with Drupal's coding conventions. Best practices in software development include keeping code clean, consistent, and readable. One aspect of this is removing nuances in code formatting by following a fixed standard.

This is particularly important on a platform such as Drupal, where thousands of developers all contribute to the code. Without coding standards, the code would become a cluttered mishmash of styles, and valuable development time would be spent merely deciphering code instead of working on it.

The Drupal site has a manual on coding standards that each Drupal developer needs to become familiar with (https://www.drupal.org/docs/develop/standards/coding-standards). It won't happen overnight; you will get better with experience, but you can also configure your IDE to, for instance, flag any issues with your code formatting.

A third resource is the change records database (https://www.drupal.org/list-changes/drupal). On this page, you'll find an inventory of the most important API and usage changes with some handy explanations. Since Drupal 8 and 9 are shipping new functionality every 6 months, this database is very important to follow.

The developer (Devel) module

On your development environment, you can install a handy module called Devel (http://drupal.org/project/devel), which provides several sophisticated tools designed to help developers create and debug Drupal code.

The following are a few of the features of this module:

  • Functions used for dumping objects and arrays into formatted Drupal output
  • Tools for analyzing database usage and performance
  • A content generator for quickly populating your site with testing content

Drush (the Drupal shell)

Sometimes, it is much easier to run some tasks with a single command in a console. Drush (http://drupal.org/project/drush) provides a command-line Drupal interface and it can be used to execute tasks with a few keystrokes at the console.

When developing, we often have to clear caches, run specific tasks, or deploy data to a remote server. Drush can help accomplish tasks like these. Additionally, we can write our own Drush commands that perform various custom tasks, for example, to be used in cron jobs. So having Drush installed is a must for any serious Drupal developer.

Developer settings

While doing local development, it's beneficial to (sometimes) disable things such as caching in order to be quicker. To do so, we can use local settings that disable caching, prevent CSS and JavaScript file aggregation, and do other similar things.

These settings are found inside the example.settings.local.php file in the /sites folder of the installation. To benefit from these, you will need to make sure that they are included in your main settings.php file (either by copying them inside or including a file like this).

A word of caution—do keep in mind that by developing with caching disabled at all times, you run the risk of overlooking certain aspects that won't work properly with caching enabled (such as invalidations). So, do try to toggle these settings on or off to ensure that a production-like environment will work just as well as under your development conditions.

Drupal check

In order to facilitate upgrading code from Drupal 8 to 9, a nice tool has been created by the community that statically runs over your code and points out all the use of deprecated code you may have. It's a command-line utility called drupal-check that is easily installable and can greatly speed up this process. Of course, you can also rely on the IDE to flag deprecated warnings.

The tool can be found here: https://github.com/mglaman/drupal-check.



This chapter has been an overview of Drupal 9 for developers. We saw what technologies Drupal uses. We took a look at Drupal's architecture. We took a cursory glance at several prominent subsystems of Drupal. We also got a feel for which developer-oriented tools are to be used while working with Drupal.

Starting with the next chapter, we will be working with code. In fact, each of the subsequent chapters will focus on practical aspects of working with Drupal.

In the next chapter, we will create our first Drupal 9 module with the obligatory Hello World example.

About the Author

  • Daniel Sipos

    Daniel Sipos is a senior web developer specializing in Drupal. He's been working with Drupal sites since version 6, and started out, like many others, as a site builder. He's a self-taught programmer with many years' experience working professionally on complex Drupal 7 and 8 projects. In his spare time, he runs webomelette, a Drupal website where he writes technical articles, tips, and techniques related to Drupal development.

    Browse publications by this author

Latest Reviews

(2 reviews total)
The book is excellent in principle, but it needs some formatting corrections.
I'd like to comment - unfortunately the book is still not ready to be published.
Book Title
Unlock this book and the full library for only $5/m
Access now