Develop
Development concepts

Drupal development concepts

⚠️
Documentation is under revision. Some contents are not complete yet.

What can Drupal custom code do?

  • Alter existing or add a new functionality
  • Integrate with third party systems
  • Provide new ways to manage, display or interact with content or users
  • ...

Let's see which Drupal concepts are used to achieve this.

There is a module for that! ™

Drupal is a modular system. It means that it is built from small pieces of code that can be enabled or disabled. These pieces of code are called modules.

One of the newcomer mistake is programming too much (opens in a new tab). If you need to implement a rather common feature, chances are that there is a module for that, so you don't have to reinvent the wheel.

Here is a short list of the most used modules.

Drupal is also pretty well integrated with the PHP ecosystem (Symfony (opens in a new tab), Composer (opens in a new tab) / Packagist (opens in a new tab), PSR's (opens in a new tab)) since version 8, so you can still find documentation outside of the Drupal scope.

OK, now it's really time to see what Drupal provides to build custom code.

Hooks and events: react to changes

Hooks

Hooks are functions that are called at a specific moment of the execution. Modules are able to implement these hooks to alter the behavior of Drupal core or other contributed modules.

They are defined in the module's .module file. For themes, they are defined in the .theme file.

How can I find which hooks are available?

For the core, hooks are defined in the API documentation (opens in a new tab).

A module can also define its own hooks. They are usually discoverable through the modules .api.php file.

A simple way to find hooks is to search for hook_ in the codebase or just let PHPStorm autocomplete the function name for you when Drupal is configured (opens in a new tab). Then type your module name and PHPStorm will provide you with a list of available hooks.

Examples of hooks

hook_form_alter

This hook is called when a form is built. It allows to alter the form rendering and its state. Has this hook has a pretty large scope, it is preferred to use more specific hooks when possible, like hook_form_FORM_ID_alter or hook_form_BASE_FORM_ID_alter.

hook_entity_type_alter

This hook is called when an entity type is defined. It allows to alter the entity type definition, for example to add a new field to all nodes.

hook_entity_insert

This hook is called when an entity is inserted in the database. It allows to react to the creation of an entity. There are various other hooks like this one, for example hook_entity_update or hook_entity_delete. Like hook_form_alter, it is preferred to use more specific hooks when possible, like hook_ENTITY_TYPE_insert or hook_ENTITY_TYPE_update.

Events

Events are objects that are dispatched at a specific moment of the execution. They are roughly similar to hooks, they are just implemented in a different way, that follows object oriented principles. Hooks are still used in Drupal, because there is a lot of legacy code that uses them, but events are the recommended way to alter the behavior of Drupal Core if it is possible to use them.

Subscribers

React to events, like Symfony RequestEvent

Dispatchers

Dispatch events, with EventDispatcher

Services: provide reusable code

How can I find which services are available?

Here is a List of core services (opens in a new tab)

Similar to hooks, PHPStorm shines here, especially with the Symfony plugin installed.

Drush can also do that: drupal debug:container then pipe it to grep to find a specific service.

Routes: define URLs

Structure of routes

Most of the time, the only thing that you need to do is to define a route in your module via a .routing.yml file.

Here is a very minimal example from the core Book module, that defines the route for a Controller method.

book.render:
  # The path always starts with a leading forward-slash.
  path: '/book'
  # Defines the default properties of a route.
  defaults:
    # For page callbacks that return a render array use _controller.
    _controller: '\Drupal\book\Controller\BookController::bookRender'
  # Require a permission to access this route.
  requirements:
    _permission: 'access content'

Same goes for a form:

my_module.route_machine_name:
  path: '/my_module/personal-info'
  defaults:
    _form: 'Drupal\my_module\Form\InfoForm'
    _title: 'Personal information'
  requirements:    
    _permission : 'custom_module_permission'

Read more (opens in a new tab) - Drupal.org

How can I discover existing routes?

With Drush drush route or the Devel (opens in a new tab) module.

And how can I find the current route used by the frontend.

There are several ways to do that:

  • Without any dependency (Drush, Devel, ...): implement a rather global hook like hook_preprocess_page and dump \Drupal::routeMatch()->getRouteName();
  • drush route --path=/the-path

Read more about Drush route (opens in a new tab)

Alter existing routes

Useful e.g. to add a new access control or to change the controller method that is called.

This is rather straigthforward, you just need to implement a RouteSubscriberInterface and implement the alterRoutes method.

Read more (opens in a new tab)

Dynamic routes

Read more (opens in a new tab) - Drupal.org

Controllers and response types: return content

  • Render array
  • Response / cacheable response
  • JSON response / JSON cacheable response
  • Binary file response

Content entities: manage content

Core entity types

  • Node: node_types are providing node content
  • Taxonomy term: vocabulary are providing taxonomy_term content
  • User

Custom content entities

Extend content entities

Configuration entities: manage configuration

Core configuration entities

We already discovered some of them: node_types and vocabularies.

  • user_role contains a set of permission configuration

Custom configuration entities

Extend configuration entities: third pary settings

Forms: provide user interaction

APIs: integrate with third party systems

Consume APIs

Serve APIs

Migration: import data from other systems

This can be used to import data from a legacy system or to migrate from another CMS once.

But it can also be used to import data from a third party system on a regular basis.

Import from another CMS or Drupal 7 site

Drupal 7 sites have their own migration system, as version 8 introduced many breaking changes in the model.

Plugin: provide extensibility and extend existing systems

Plugin manager, plugin types, plugin discovery

Field plugins

Mailing: send emails

Decorators: alter existing code

Permission: define access to content and functionality

  • Access handlers

Caching

Cache API (opens in a new tab) - Drupal.org

Validation: forms and contraints

Validate a form

Form API - validation (opens in a new tab) - Drupal.org

Alter an existing form

Constraints

Entity validation API overview (opens in a new tab) - Drupal.org Validation constraints (opens in a new tab) - Drupal.org