Skip to main content

Drupal Dependency Injection: Plugins

Back-end Development
Drupal

I am writing a Drupal plugin (like a block or field formatter). How do I access a service in the correct way?

Many plugin base classes (such as blocks) do not already implement ContainerFactoryPluginInterface, so you should declare this implementation. Then in the definition of the class, you will implement a create method that uses $container->get() to fetch and store each of the needed services.

If the plugin base class does implement ContainerFactoryPluginInterface, you can follow the same pattern as controllers, by calling parent::create to get the instance. However, in cases like blocks that do not implement this, you will instead need to create the instance with a standard new call to the class name.

For example:

<?php

namespace Drupal\services_examples\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\services_examples\ExampleServiceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a block with the current date.
 *
 * @Block(
 *   id = "services_examples_date",
 *   admin_label = @Translation("Current Date")
 * )
 */
class DateBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The time service.
   *
   * @var \Drupal\services_examples\ExampleServiceInterface
   */
  protected ExampleServiceInterface $exampleService;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $plugin = new static(
      $configuration,
      $plugin_id,
      $plugin_definition
    );

    $plugin->exampleService = $container->get('services_examples.custom_service');

    return $plugin;
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      '#type' => 'html_tag',
      '#tag' => 'p',
      '#value' => $this->exampleService->getCurrentDate(),
    ];
  }

}

By doing this, we have made the service available in our block subclass, while not upsetting the required constructor behavior of the parent class.