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.
Need a fresh perspective on a tough project?
Let’s talk about how RDG can help.