function ModuleHandler::getCombinedListeners
Same name and namespace in other branches
- 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\ExtensionCode
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.