Skip to content
Demonstrative example on how to swap a service with dependency injection containers
PHP
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
lib/Drupal/countries_fifa
.gitignore
README.md
countries_fifa.info.yml
countries_fifa.module
countries_fifa.services.yml

README.md

Drupal 8 services dependency injection

Demonstrative example on how to swap a service with dependency injection.

Motivation

Drupal 8 provides swapable services that can be altered or even replaced by using dependency injection compiler passes. The purpose of this module is to display a straightforward way to do it. The example will replace the countries service by the country list provided by another authorised entity, such as the FIFA, which works with a different set of rules :).

Step 1: Create the module structure

As for Drupal 8, you need a .info.yml file declaring your module and a .module file. Alternatively, we're relying on PSR-0 for loading the libraries, so a lib/Drupal/countries_fifa folder will be needed too. You could use whatever structure inside lib/Drupal folder if you update the namespaces accordingly.

Step 2: Building an alternative service

Declaring a new service in Drupal 8 has two parts, a .services.yml file and the class that provides the service.

This is the countries_fifa.services.yml file, note that you need to respect the namespaces to get PSR-0 working. You could send whatever arguments you might need, in this case I wanted to keep it simple.

services:
  fifa_country_manager:
    class: Drupal\countries_fifa\FifaCountryManager
    arguments: [{  }, {  }]

The class we need is extending/replacing the country list, so it needs to extend & include CountryManagerInterface.

namespace Drupal\countries_fifa;

use Drupal\Core\Locale\CountryManagerInterface;

/**
 * Provides list of countries coming from the FIFA.
 */
class FifaCountryManager implements CountryManagerInterface {

Step 3: The compiler pass

Service containers are compiled into a cached file that lives in our files/php folder, before this happen, the configuration files are processed by the compiler passes that build this file that is then used by Drupal and its symfony components to locate and use the services.

What we're doing in this compiler pass is telling the Depenency injection container that instead of using the default country list provided by the service country_manager, uses ours.

namespace Drupal\countries_fifa;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

/**
 * Replaces country list by the one provided by the FIFA.
 */
class FifaCountryManagerPass implements CompilerPassInterface {

  /**
   * Replaces country list by the one provided by the FIFA.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
   *   The container to process.
   */
  public function process(ContainerBuilder $container) {
    $definition = $container->getDefinition('country_manager');
    $definition->setClass('Drupal\countries_fifa\FifaCountryManager');
  }

}

We could potentially do other stuff in here, such as validations and alterations, not just plain replacement. Think of this as of a very sophisticated hook_alter.

Step 4: The Bundle

There's still another thing we need to do in order to get the service altered, we need to declare a Bundle component that will add the compiler pass declared on step 3 using addCompilerPass method.

namespace Drupal\countries_fifa;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * FIFA country manager dependency injection container.
 */
class CountriesFifaBundle extends Bundle {

  /**
   * Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build().
   */
  public function build(ContainerBuilder $container) {
    $container->addCompilerPass(new FifaCountryManagerPass());
  }
}
</code>

References

Something went wrong with that request. Please try again.