function HookOrder::changePriority
Change the priority of a hook implementation.
Parameters
\Drupal\Core\DependencyInjection\ContainerBuilder $container: The container builder.
string $hook: The name of the hook.
string $class_and_method: Class and method separated by :: containing the hook implementation which should be changed.
bool $should_be_larger: TRUE for before/first, FALSE for after/last. Larger priority listeners fire first.
array|null $others: Other hook implementations to compare to, if any. The array is keyed by string containing a class and method separated by ::, the value is not used.
Return value
void
4 calls to HookOrder::changePriority()
- HookOrder::after in core/
lib/ Drupal/ Core/ Hook/ HookOrder.php - Set a hook implementation to fire after others.
- HookOrder::before in core/
lib/ Drupal/ Core/ Hook/ HookOrder.php - Set a hook implementation to fire before others.
- HookOrder::first in core/
lib/ Drupal/ Core/ Hook/ HookOrder.php - Set a hook implementation to be first.
- HookOrder::last in core/
lib/ Drupal/ Core/ Hook/ HookOrder.php - Set a hook implementation to be last.
File
-
core/
lib/ Drupal/ Core/ Hook/ HookOrder.php, line 114
Class
- HookOrder
- Helper methods to set priorities of hook implementations.
Namespace
Drupal\Core\HookCode
protected static function changePriority(ContainerBuilder $container, string $hook, string $class_and_method, bool $should_be_larger, ?array $others = NULL) : void {
$event = "drupal_hook.{$hook}";
foreach ($container->findTaggedServiceIds('kernel.event_listener') as $id => $attributes) {
foreach ($attributes as $key => $tag) {
if ($tag['event'] === $event) {
$index = "{$id}.{$key}";
$priority = $tag['priority'];
// Symfony documents event listener priorities to be integers,
// HookCollectorPass sets them to be integers, ::setPriority() only
// accepts integers.
assert(is_int($priority));
$priorities[$index] = $priority;
$specifier = "{$id}::" . $tag['method'];
if ($class_and_method === $specifier) {
$index_this = $index;
}
elseif (!isset($others) || isset($others[$specifier])) {
$priorities_other[] = $priority;
}
}
}
}
if (!isset($index_this) || !isset($priorities) || !isset($priorities_other)) {
return;
}
// The priority of the hook being changed.
$priority_this = $priorities[$index_this];
// The priority of the hook being compared to.
$priority_other = $should_be_larger ? max($priorities_other) : min($priorities_other);
// If the order is correct there is nothing to do. If the two priorities
// are the same then the order is undefined and so it can't be correct.
// If they are not the same and $priority_this is already larger exactly
// when $should_be_larger says then it's the correct order.
if ($priority_this !== $priority_other && $should_be_larger === $priority_this > $priority_other) {
return;
}
$priority_new = $priority_other + ($should_be_larger ? 1 : -1);
// For ::first() / ::last() this new priority is already larger/smaller
// than all existing priorities but for ::before() / ::after() it might
// belong to an already existing hook. In this case set the new priority
// temporarily to be halfway between $priority_other and $priority_new
// then give all hook implementations new, integer priorities keeping this
// new order. This ensures the hook implementation being changed is in the
// right order relative to both $priority_other and the hook whose
// priority was $priority_new.
if (in_array($priority_new, $priorities)) {
$priorities[$index_this] = $priority_other + ($should_be_larger ? 0.5 : -0.5);
asort($priorities);
$changed_indexes = array_keys($priorities);
$priorities = array_combine($changed_indexes, range(1, count($changed_indexes)));
}
else {
$priorities[$index_this] = $priority_new;
$changed_indexes = [
$index_this,
];
}
foreach ($changed_indexes as $index) {
[
$id,
$key,
] = explode('.', $index);
self::setPriority($container, $id, (int) $key, $priorities[$index]);
}
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.