How to declare a custom service in your own Drupal 8 module
Using Dependency injection. Why?
Dependency injection is the concept of decoupled reusable functionality. This means we can write better and efficient code by reducing the execution time that’s why this is the preferred method and also because it is useful in writing Unit Tests.
If we look in the core of Drupal 8 we see a file named "core.services.yml". This file stores most of the services used within the core.
Here's an example:
services: path.current: class: Drupal\Core\Path\CurrentPathStack arguments: ['@request_stack']
"path.current": is the name of the service for getting and setting the path
“class”: the class which implements the service
“arguments”: represents the name of the service that needs to be injected inside the service, in this case "request_stack"
To access the "path.current" service in the static context we should call the service container.
$currentPath = \Drupal::service('path.current'); $path = $currentPath->getPath();
Declare your own service
Suppose we have a custom module called: "mymodule", we need to create in the module’s folder a file named "mymodule.services.yml". The name of the service doesn't have a naming standard, but it is a best practice to start with the name of the module followed by a specific action.
services: mymodule.tools: class: Drupal\mymodule\MyTools arguments: ['@database']
My service is called "mymodule.tools" and it is implemented in the "MyTools" class and is dependant of the "database" core service.
/** * Class MyTools. */ class MyTools { /* * @var \Drupal\Core\Database\Connection $database */ protected $database; /** * Constructs a new MyTools object. * @param \Drupal\Core\Database\Connection $connection */ public function __construct(Connection $connection) { $this->database = $connection; } /** * Show the author of the node. * * @param int $nid * The node id. * * @return int * Return the uid. */ public function showAuthor ($nid) { $query = $this->database->select('node_field_data', 'nfd'); $query->condition('nfd.nid', $nid); $query->fields('nfd', ['uid']); $result = $query->execute()->fetchAll(); if (!empty($result)) { return $result[0]->uid; } } }
My custom service uses the "database" core service. The "database" core service is injected in my service. We can access this custom service and call the showAuthor() function by:
$callService = \Drupal::service('mymodule.tools'); $callService->showAuthor(15);
How to access the service?
1. In procedural programming we could use the service container:
\Drupal::service('path.current'); // This is not recommended in OOP.
2. Injecting in the other classes/services.(Shown in the above example)