function ModuleHandler::getCombinedListeners

Same name and namespace in other branches
  1. 11.x core/lib/Drupal/Core/Extension/ModuleHandler.php \Drupal\Core\Extension\ModuleHandler::getCombinedListeners()

Builds a list of implementations for an alter hook.

Parameters

list<string> $hooks: The hooks passed to the ->alter() call.

Return value

list<callable> List of implementation callables.

1 call to ModuleHandler::getCombinedListeners()
ModuleHandler::alter in core/lib/Drupal/Core/Extension/ModuleHandler.php
Passes alterable variables to specific hook_TYPE_alter() implementations.

File

core/lib/Drupal/Core/Extension/ModuleHandler.php, line 420

Class

ModuleHandler
Class that manages modules in a Drupal installation.

Namespace

Drupal\Core\Extension

Code

protected function getCombinedListeners(array $hooks) : array {
  // Get implementation lists for each hook.
  /** @var list<\Drupal\Core\Hook\ImplementationList> $lists */
  $lists = array_map($this->getHookImplementationList(...), $hooks);
  // Remove empty lists.
  /** @var array<int, \Drupal\Core\Hook\ImplementationList> $lists */
  $lists = array_filter($lists, fn(ImplementationList $list) => $list->hasImplementations());
  if (!$lists) {
    // No implementations exist.
    return [];
  }
  if (array_keys($lists) === [
    0,
  ]) {
    // Only the first hook has implementations.
    return $lists[0]->listeners;
  }
  // Collect the lists from each hook and group the listeners by module.
  $listeners_by_identifier = [];
  $modules_by_identifier = [];
  $identifiers_by_module = [];
  foreach ($lists as $list) {
    foreach ($list->iterateByModule() as $module => $listener) {
      $identifier = is_array($listener) ? get_class($listener[0]) . '::' . $listener[1] : $listener;
      $other_module = $modules_by_identifier[$identifier] ?? NULL;
      if ($other_module !== NULL) {
        $this->triggerErrorForDuplicateAlterHookListener($hooks, $module, $other_module, $listener, $identifier);
        // Don't add the same listener more than once.
        continue;
      }
      $listeners_by_identifier[$identifier] = $listener;
      $modules_by_identifier[$identifier] = $module;
      $identifiers_by_module[$module][] = $identifier;
    }
  }
  // First we get the the modules in moduleList order, this order is module
  // weight then alphabetical. Finally we order using order attributes.
  $modules = array_keys($identifiers_by_module);
  // Order by module order first, this preserves expected order for alter
  // hooks implemented on behalf of other modules. The module that hooks
  // implementations in kernel test classes are grouped by is 'core'. Since
  // 'core' is not actually a module, add 'core' as a key to the module list,
  // so core implementations are not filtered out. 'Core' is added last to
  // match how kernel test hooks are added last by KernelTestCompilerPass.
  // @todo Determine whether 'core' should still be ordered last by default
  //   when any service, including in the Drupal\Core namespace, can have
  //   hook implementations.
  // @see https://www.drupal.org/i/3481903.
  $modules = array_intersect(array_keys($this->moduleList + [
    'core' => '',
  ]), $modules);
  // Create a flat list of identifiers.
  $identifiers = array_merge(...array_map(fn(string $module) => $identifiers_by_module[$module], $modules));
  foreach ($hooks as $hook) {
    foreach ($this->getHookOrderingRules($hook) as $rule) {
      $rule->apply($identifiers, $modules_by_identifier);
      // Order operations must not:
      // - Insert duplicate keys.
      // - Change the array to be not a list.
      // - Add or remove values.
      assert($identifiers === array_unique($identifiers));
      assert(array_is_list($identifiers));
      assert(!array_diff($identifiers, array_keys($modules_by_identifier)));
      assert(!array_diff(array_keys($modules_by_identifier), $identifiers));
    }
  }
  return array_map(static fn(string $identifier) => $listeners_by_identifier[$identifier], $identifiers);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.