Drupal How To: Override a Core Drupal 8 Service
Drupal 8 brings with it some sophisticated tools and functionality that make it an amazing content management system right out-of-the-box. But sometimes the default functionality doesn’t give you exactly what you need for your website's business requirements. But don’t despair! With Drupal 8's Symfony underpinnings, we can easily modify Drupal’s default functionality to meet our needs.
Sometimes we can use hooks or event subscribers to make the modifications we need. In some cases, it’s necessary to change the functionality of a service.
As we were nearing completion of work on a client’s new content hub, we needed to make some modifications to how Drupal generated each link across the site to meet the unique business requirements of their site. For what we needed to do, using hook_link_alter() didn’t meet our needs. In this quick tutorial, we’ll show you how we did this. Whether you need to override this or another one of Drupal’s core services, the process is the same.
Step 1 – Create a module to override the core service
The code you write to modify the core service is housed in a custom module. This can be in a standalone custom module just for this, or it can be incorporated into another module if that makes sense in your situation. For our example, we are going to create a new module called my_module.
For now, this consists of two files: my_module.info.yml (just a basic Drupal 8 module info file) and my_module.module (a file with <?php and a blank line, but otherwise empty).
Step 2 – Determine the service to override
My preferred way to determine the service to override is to use the services explorer in the Webprofiler module. This shows all of the services from the container and which ID to use. In this case, we’re going to be modifying links, so we’ll need the link_generator service.
Step 3 – Tell Drupal to use your service instead of Core’s
Since we are overriding an already-existing service, we don’t have to create a my_module.services.yml file. However, we do need to add a special file that tells Drupal of our intent to override the Link Generator service.
If you don’t already have a ‘src’ directory in your module, create it. Next, create a file named MyModuleServiceProvider.php. This file’s name must be the name of your module in camel case (my_module is converted to MyModule) followed by ServiceProvider.php. The naming of this file is important as Drupal looks for a file following this naming convention when the module is enabled. If it finds this file, Drupal then knows that you intend to override a service.
The class inside this file has the same name as the file name. The class needs to extend ServiceProviderBase and implement ServiceProviderInterface. For our module, this file looks like this:
The ServiceProviderInterface has one function (alter), which we use to tell Drupal about our replacement service. We do this by first obtaining the definition for the existing service (in line 11) and then using the setClass method in link 12 to use our module’s MyLinkGenerator class instead of Drupal’s LinkGenerator class.
Step 4 – Create the overriding class
Now that the hard part is complete, we need to now create the MyLinkGenerator class!
Create the file /my_module/src/MyLinkGenerator/MyLinkGenerator.php (making the necessary MyLinkGenerator directory). In this file, we need to simply create the MyLinkGenerator class, which extends core’s LinkGeneratorClass and implements LinkGeneratorInterface.
From here, you can define any of the methods in core’s LinkGeneratorInterface and replace it with your custom functionality. Taking the generate() method as an example, we can define it as a public function, called parent::generate to get the default output, and then modify it as needed.
In the above code, we are using parent::generate to get the default output from the generate method of LinkGenerator and setting it to the variable $generatedLink. From here, we can do whatever customizations to it (// Do your magic here!) before returning.
If you need to customize a large portion of the code, consider copying the code from the core method into your class and use it as a starting point for your custom needs. As demonstrated here, Drupal 8 can easily be tailored to meet your very-specific needs!