Introduction to Annotations in Drupal 8

Annotations are another one of the new concepts in Drupal 8 to wrap your head around. Annotations are written as PHP code comments above a class or function and contain metadata about the function or class.

Annotations are used by other PHP projects. For example, Symfony2 uses annotations for routing rules and Doctrine uses them for ORM related meta data.

Annotations used by D8’s Plugin system

As it stands, Annotations are only used by the Plugin system in Drupal 8. They provide the mechanism for which Plugins are discovered by Drupal and describe their meta data.

Plugin discovery

One of the major conceptual changes in Drupal 8 is that Drupal is not aware of your code until you specifically tell it about your code.

In module development you tell Drupal about the module in a info.yml file. You tell Drupal about specific routes in route YAML files. You tell Drupal which menu links to add to the menu system in menu YAML files. Annotations are a similar concept for Plugins. Rather than having a YAML file for each plugin, you have an annotation and Drupal will automatically find (discover) the plugin.

Example plugin types

Blocks are the most common type of plugin in Drupal 8. But they are by no means the only type. Plugins include:

  • Blocks
  • Field formatters
  • Views plugins
  • Conditions
  • Migrate source

See Drupal.org for more information on Annotation-based plugins.

Example Annotation

Here is a quick example of an annotation for a block class:

/**
 * Provides a 'Welcome' Block
 *
 * @Block(
 *   id = "welcome_block",
 *   admin_label = "Welcome block",
 * )
 */

Block manager scans files looking for @Block annotation tag to find block instances.

The @Block annotation ensures that the block manager discovers this custom block and makes it available to be added to a region. The id of welcome_block is the machine name and the admin_label (Hello block) will appear in the block interface’s list of blocks.

Annotation parser

Annotations are read and parsed at runtime by an annotation engine. Drupal 8 uses the Doctrine annotation parser, which turns it into an object that PHP can use.

How is this different to Drupal 7?

In Drupal 7, meta data live in info hooks.

Let’s have a look at a custom block in Drupal 7 to demonstrate:

/**
 * Implements hook_block_info().
 */
function first_module_block_info() {
  $blocks = array();
  $blocks['first_block'] = array(
    'info' => t('First block'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function first_module_block_view($block_name = '') {
  if ($block_name == 'first_block') {
    $content = variable_get('first_block_content', 'Some content');
    $block = array(
      'subject' => t('Sample block'),
      'content' => t(‘Sample block content’),
    );

    return $block;
  }
}

The block is registered with Drupal in first_module_block_info(), which implements hook_block_info(). Without this, Drupal wouldn’t know that the block exists and it would not appear in the block admin screen.

The problem with this approach is that .module files need to be read and stored in memory at runtime, using a more than ideal amount of memory.

Advantages of annotations

Performance improvement

Annotations use less memory than the D7 way and alternatives in D8.

In Drupal 7, each module’s .module file is read into memory for every request. In Drupal 8, an alternative to annotations is to have a getInfo method for each plugin class. But this would mean the class has to be loaded into memory to get this information and the memory is not freed up until the end of the request. This increases the amount of memory needed.

Annotations are tokenised and do not use as much memory. They are only loaded into memory and instantiated when their functionality is needed. Also, docblocks are cached by an opcode cache.

Live in the same file

Annotations live in the same file as the class that implements a plugin, so they are easier to find.

Drupal Annotation Syntax

Drupal’s Annotation syntax is heavily borrowed from Doctrines (but it is not exactly the same).

Annotations comprise of nested key value pairs and support nesting.

@Plugin

The annotation comment has to start with @Plugin, where “Plugin” is the type of plugin. In the example above, @Block was used because the annotation is for a plugin of type block.

keys

Keys on the root level should either have double quotes or no quotes at all. The general recommendation is to skip quotes unless the key name contains spaces.

In the block example above, there are two keys, id and admin_label. Neither of these have quotes.

Sub level keys must use double quotes.

Translatable text

Translatable strings should be wrapped in @Translation().

Values

  • strings - double quotes
  • lists - curly brackets
  • quotes within a string: use double quotes
  • maps - use curly brackets and equality sign to separate the key and the value
  • booleans - TRUE and FALSE (no quotes)
  • numbers - no quotes

Summary

  • Most info hooks replaced with annotations
  • Drupal’s annotation syntax borrowed from Doctrine
  • Can be used for any purpose - Drupal 8 currently uses for plugin system
  • Lives in the same file as the class that implements a plugin and is therefore easier to find
  • Uses less memory than the Drupal 7 method and raw PHP alternatives in Drupal 8

Drupal 8: Controllers, Routes, Form classes, the death of hooks? Oh my, so many changes! What do I start?!

Learn the first steps in starting your new Drupal module in just 20 minutes per day. You’ll get your feet wet in the new world of Drupal 8 module development and get over the hardest hurdle of all - getting started without being overwhelmed.

Get the free 7 day course

Add new comment