Drupal Service ID Collectors

Drupal Service ID Collectors

Since Drupal 8 we've had services. This also brought the concept of a service collector or tagged services. This allows services to be tagged with a specific tag, then a service collector can collect all services with the a given tag and use whichever service "applies".

As you could imagine loaded all of these tagged services when loading the service collector service can be a performance nightmare, which is why Drupal 8.4.0 brought us service ID collector functionality.

Tagging a service with the service_id_collector tag will pass all services with a given tag as the last parameter in the constructor. This will be an array of service IDs ordered by the priority. You will then need to use the ClassResolver service to lazily instantiate the collected service IDs.

my_module.services.yml
my_module.negotiator:
  class: \Drupal\my_module\MyModuleNegotiator
  arguments: {'@class.resolver'}
  tags:
    - { name: service_id_collector, tag: my_module_negotiator }
my_module.negotiator.foo:
  class:\Drupal\my_module\FooNegotiator
  arguments: {'@entity_type.manager'}
  tags:
    - { name: my_module_negotiator, priority: 100 }
my_module.negotiator.bar:
  class:\Drupal\my_module\BarNegotiator
  arguments: {'@entity_type.manager'}
  tags:
    - { name: my_module_negotiator, priority: -100 }
my_module.negotiator.baz:
  class:\Drupal\my_module\BazNegotiator
  arguments: {'@entity_type.manager'}
  tags:
    - { name: my_module_negotiator, priority: 0 }

MyModuleNegotiator.php
/**
 * The negotiator for my module.
 */
class MyModuleNegotiator {

  /**
   * The class resolver service.
   *
   * @var \Drupal\Core\DependencyInjection\ClassResolver
   */
  protected $classResolver;

  /**
   * The negotiator service IDs.
   *
   * @var array
   */
  protected $negotiatorServiceIds;

  /**
   * Constructs the negotiator.
   *
   * @param \Drupal\Core\DependencyInjection\ClassResolver $class_resolver

   *   The class resolver service.
   * @param array $negotiator_service_ids
   *   The negotiator service IDs.
   */

  public function __construct(ClassResolverInterface $class_resolver, array $negotiator_service_ids) {
    $this->classResolver = $class_resolver;
    $this->negotiatorServiceIds = $negotiator_service_ids;
  }

  /**
   * Run the negotiators.
   */
  public function runNegotiators() {
    foreach ($this->negotiatorServiceIds as $negotiator_service_id) {
      $negotiator = $this->classResolver->getInstanceFromDefinition($negotiator_service_id);
      if ($negotiator->applies()) {
        $negotiator->run();
      }
    }
  }
}

timmillwood Thu, 14/12/2017 - 09:29

Comment

Add new comment