Injecting core or custom services into your servicefor Drupal 8 , 9 , 10 , and 11

Last updated :  

Introduction

As you become more proficient in Drupal module development, understanding how to inject core or custom services into your own services is pivotal. This strategy facilitates the creation of more adaptable and streamlined Drupal applications. In this lesson, we will delve into the concept of service injection, which not only enhances the modularity of your code but also encourages the adherence to the principle of dependency injection.

Understanding Service Injection

Service injection is a design pattern used to make code flexible and easy to manage by providing instances of classes to an object from the outside. In Drupal, this means using the services offered by Drupal core or other modules within your custom services without directly relying on global calls or hardcoded instances.

Why Use Service Injection?

Injecting services into your custom service has several advantages:

  • Modularity: Break down functionality into distinct services that can be mixed and matched as needed.
  • Testability: Simplify testing by mocking dependencies during unit tests.
  • Decoupling: Separate concerns to allow for more significant flexibility in code changes and maintenance.

Steps to Inject Core or Custom Services

To illustrate how to inject services into your custom service, we will enhance our previous example by adding a time service. We'll demonstrate dependency injection using core services and another custom service.

Step 1: Update the Service Definition

Add an additional service to your example_module.services.yml file:


    services:
      example_module.custom_service:
        class: Drupal\example_module\CustomService
        arguments: ['@logger.channel.example_module', '@datetime.time']
    

Here, the datetime.time is a core service that provides a unified API for dealing with time operations.

Step 2: Modify the Custom Service Class

Adjust your CustomService.php class to include methods utilizing both the logger and time service:


    namespace Drupal\example_module;

    use Psr\Log\LoggerInterface;
    use Drupal\Component\Datetime\TimeInterface;

    class CustomService {

        protected $logger;
        protected $timeService;

        public function __construct(LoggerInterface $logger, TimeInterface $timeService) {
            $this->logger = $logger;
            $this->timeService = $timeService;
        }

        public function logMessageWithTimestamp($message) {
            $timestamp = $this->timeService->getCurrentTime();
            $formatted_message = sprintf('%s at %s', $message, date('Y-m-d H:i:s', $timestamp));
            $this->logger->info($formatted_message);
        }
    }
    

The method logMessageWithTimestamp() logs a message along with the current timestamp, showcasing the combination of services.

Step 3: Implement Another Custom Service

Consider you want to create a greeting service that also utilizes the CustomService:

Define it in example_module.services.yml:


    services:
      example_module.greeting_service:
        class: Drupal\example_module\GreetingService
        arguments: ['@example_module.custom_service']
    

Step 4: Create the Greeting Service Class

Create GreetingService.php and utilize the injected custom service:


    namespace Drupal\example_module;

    class GreetingService {

        protected $customService;

        public function __construct(CustomService $customService) {
            $this->customService = $customService;
        }

        public function generateGreeting($name) {
            $message = sprintf('Hello, %s!', $name);
            $this->customService->logMessageWithTimestamp($message);
        }
    }
    

This service uses the CustomService to log a personalized greeting along with a timestamp, demonstrating how custom services can be stacked and interrelated.

Best Practices

  • Keep Dependencies Clean: Inject only services that are necessary to avoid complications.
  • Document Appropriately: Clearly define the purpose and usage of each service and their dependencies.
  • Mock in Testing: Use mocks or stubs for testing services to isolate functionality during development.

Common Challenges

Issues that may arise when injecting services include:

  • Circular Dependencies: Avoid situations where two or more services depend on each other, creating loops.
  • Performance Overhead: Minimize overhead by not injecting services that will not be used frequently.

Conclusion

Service injection is a critical component of modern Drupal development, enhancing the modularity and maintainability of your code. By mastering this technique, you not only improve the organization of your services but also streamline the management of dependencies across your system.

What’s Next?

In our upcoming lesson, we'll focus on building a PHP class for the custom service. This tutorial will lay further groundwork for effective service creation and management, delving into the intricacies of creating robust, efficient classes in Drupal.