Skip to main content

Back-End Development

How to Craft Your Own Tailored Drupal Service: A Step-by-Step Guide

Istock 1289560658

Service:

A service is any object managed by the services container.

Services in Drupal help decouple reusable functionality, making them pluggable and replaceable by registering them with a service container. Services act as unsung heroes, playing a crucial role in maintaining the smooth functioning of the Drupal system.

There are Core services available in Drupal. All services are defined in the ‘CoreServiceProvider.php’ and ‘core.services.yml’ files within Drupal. To get the list of services, you can follow the service list.
Utilize dependency injection as the preferred approach for accessing and leveraging services in Drupal and deploy it whenever feasible.

Steps to Define a Custom Service in Drupal:

  • Set Up a Custom Module:

    Define the basic information about the custom module in the *.info.yml file.

    name: General
    description: All general activities.
    type: module
    core_version_requirement: ^9 || ^10
  • Creating the Service Class:

    Separate all service files by creating a ‘Services’ folder inside the ‘src’ directory. Create a PHP file in the ‘Services’ directory containing your service class, e.g., YourService.php.

    <?php
    
    namespace Drupal\general\Services;
    
    use Drupal\Core\Session\AccountProxy;
    
    /**
     * This is a custom service class.
     */
    class CustomService {
    
      /**
       * The custom service for additional logic.
       *
       * @var \Drupal\general\Services\CustomService
       */
      protected $additionalLogicService;
    
      /**
       * The current user service.
       *
       * @var \Drupal\Core\Session\AccountProxy
       */
      protected $currentUser;
    
      /**
       * Constructor for the CustomService class.
       *
       * @param \Drupal\Core\Session\AccountProxy $currentUser
       *   The current user service.
       */
      public function __construct(AccountProxy $currentUser) {
        $this->currentUser = $currentUser;
      }
    
      /**
       * Provides custom logic information.
       *
       * @return string
       *   A message indicating custom logic information.
       */
      public function provideCustomLogicInfo() {
        return "Custom logic information: ";
      }
    
      /**
       * Retrieves the display name of the current user.
       *
       * @return string
       *   The display name of the current user.
       */
      public function getCurrentUserName() {
        return $this->currentUser->getDisplayName();
      }
    
    }
    

    Defines a ‘CustomService’ class and two protected properties: ‘$additionalLogicService’ and ‘$currentUser.’ The ‘$currentUser’ property stores instances of other classes with which the CustomService class interacts.

    The constructor of this class takes an argument of type `Drupal\Core\Session\AccountProxy.` This argument usually represents the current user and is assigned to the `$currentUser` property. This is an example of dependency injection, where the constructor provides the required dependencies to the class.

     

    /**
     * Provides custom logic information.
     *
     * @return string
     *   A message indicating custom logic information.
     */
    public function provideCustomLogicInfo() {
      return "Custom logic information: ";
    }
    
    /**
     * Retrieves the display name of the current user.
     *
     * @return string
     *   The display name of the current user.
     */
    public function getCurrentUserName() {
      return $this->currentUser->getDisplayName();
    }

    The ‘provideCustomLogicInfo()’ function yields a fundamental text string, whereas ‘getCurrentUserName()’ actively fetches the display name of the currently logged-in user through the ‘$currentUser’ object. These steps demonstrate the structure of a service class in Drupal, which includes properties, constructors, and methods. To employ this class as a service in Drupal, ensure its registration in the ‘general.services.yml’ file and explicitly specify both the class and its dependencies.

  • Creating a Service Definition:

    Create a ‘*.services.yml’ file in the module directory. The filename should be ‘module_name.services.yml.’ For example, ‘general.services.yml.’ This file defines the services and their corresponding classes for the Drupal module.

    services:
      general.custom_service:
        class: Drupal\general\Services\CustomService
        arguments: ['@current_user']
    1. General.custom_service: The unique machine name for service. Pattern ‘module_name.unique_name’.
    2. Class: The fully-qualified namespace of your service class.
    3. Arguments: Passing arguments to the service constructor. In this case, use the ‘@current_user’ core service to get the user’s Display name.
  • Use Custom Services through Dependency Injection:

    Now, use custom service in other parts or even in other modules. For example, in a controller or another service, use dependency injection to access a custom service. As an example, accessing service via the Controller

    <?php
    
    namespace Drupal\general\Controller;
    
    use Drupal\Core\Controller\ControllerBase;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Drupal\general\Services\CustomService;
    
    class UsernameController extends ControllerBase {
    
      /**
       * The custom service for handling user information.
       *
       * @var \Drupal\general\Services\CustomService
       */
      protected $customService;
    
      /**
       * Constructs a new UsernameController object.
       *
       * @param \Drupal\general\Services\CustomService $customService
       *   The custom service for handling user information.
       */
      public function __construct(CustomService $customService) {
        $this->customService = $customService;
      }
    
      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container) {
        return new static(
          $container->get('general.custom_service'),
        );
      }
    
      /**
       * Render the user information using the custom service.
       *
       * @return array
       *   A render array.
       */
      public function renderUserInfo() {
        return [
          '#type' => 'markup',
          '#markup' => $this->customService->provideCustomLogicInfo() . $this->customService->getCurrentUserName(),
        ];
      }
    
    }
    

    In Controller, we need to import the necessary classes. Also, remember to import Custom service. Protected property $customService to store an instance of the ‘CustomService’ class.

    /**
     * Constructs a new UsernameController object.
     *
     * @param \Drupal\general\Services\CustomService $customService
     *   The custom service for handling user information.
     */
    public function __construct(CustomService $customService) {
      $this->customService = $customService;
    }

    The constructor is responsible for initializing the controller object. It takes an instance of ‘CustomService’ as an argument, injecting it into the Controller. This is an example of dependency injection, where the required dependency (CustomService) is provided through the constructor.

    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container) {
      return new static(
        $container->get('general.custom_service'),
      );
    }

    The create method is a factory method used by Drupal’s dependency injection container. It creates a new instance of the ‘UsernameController’ class and injects the required dependencies. In this case, it retrieves the CustomService instance from the container using ‘$container->get(‘general.custom_service’)’.

    /**
     * Render the user information using the custom service.
     *
     * @return array
     *   A render array.
     */
    public function renderUserInfo() {
      return [
        '#type' => 'markup',
        '#markup' => $this->customService->provideCustomLogicInfo() . $this->customService->getCurrentUserName(),
      ];
    }

    This method, ‘renderUserInfo(),’ is responsible for rendering user information using the methods provided by the injected CustomService. It returns a render array, which could be used to display content on a Drupal page.

    The dependency injection here, especially in the constructor and the create method, ensures that the UsernameController class is not tightly coupled to the concrete implementation of CustomService, making it more flexible and accessible to test. It also follows Drupal’s best practices for service instantiation and usage.

  • Clear cache:

    After creating or modifying your service and service definition, clear Drupal’s cache using Drush  (drush cr) or the admin interface.
    Output For Services
    That’s it! Successfully created a custom service in Drupal. Adjust the service class and definition based on your specific functionality.

Thoughts on “How to Craft Your Own Tailored Drupal Service: A Step-by-Step Guide”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Sanket Milmile

Sanket Milmile is an associate technical consultant and Drupal developer. He is enthusiastic about acquiring new skills, learning, and exploring technologies.

More from this Author

Follow Us
TwitterLinkedinFacebookYoutubeInstagram