Services registered in core.services.yml or a module's module.services.yml can now be used to implement hooks. The same Drupal\Core\Hook\Attribute\Hook documented in "Support for object oriented hook implementations using autowired services" can be added to a class (or class method) registered as a service, regardless of where in src directory structure the class file exists.
There are exceptions. The following are the kinds of services that are excluded from hook implementation discovery:
- Services whose classes are outside the
Drupalnamespace, or inDrupal\Component - Abstract services
- Synthetic services
- Services defined by a factory
- Deprecated services
- Services that decorate other services
- Classes for services that are dynamically provided or modified by a module's service modifier/provider. If a service modifier alters an existing hook service, an error will be thrown
Services in a module's Hook\ namespace that are autodiscovered can not be decorated or altered. Registered services that have hook implementations can be decorated or altered; however, as mentioned, any hook implementations in the decorating or altered service class will not be invoked, and the hook implementations in the original class will still be invoked.
The API to alter existing hook implementations is to use the order property in the Hook attribute, or the ReorderHook and RemoveHook attributes. To target hook methods on an registered service, use the FQCN of the class of the service, and not the service ID.
Example
module_a.services.yml
services:
module_a.hook_service:
class: Drupal\module_a\HookServiceA
HookServiceA.php
namespace Drupal\module_a;
use Drupal\Core\Hook\Attribute\Hook;
class HookServiceA {
#[Hook('test_hook')]
public function testHook(): {
// ...
}
}
module_b.services.yml
services:
module_b.hook_service:
class: Drupal\module_b\HookServiceB
HookServiceB.php
namespace Drupal\module_b;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\Hook\Order\OrderBefore;
use Drupal\module_a\HookServiceA;
class HookService B{
#[Hook(
hook: 'test_hook',
order: new OrderBefore(classesAndMethods: [[HookServiceA::class, 'testHook']])),
]
public function testHook(): {
// ...
}
}
When ordering or removing, if you are targeting a service in the Drupal\Core namespace, you can use coreas the target module.
Deprecations
To support this functionality, decorating or altering Drupal\{module}\Hook\* services is deprecated in Drupal 11.5.0 and will cause an error to be thrown in Drupal 12. Instead of decorating or altering the Hook classes, the
Drupal\Core\Hook\Attribute\ReorderHook or Drupal\Core\Hook\Attribute\RemoveHook attributes can be used on service class methods to target other hook methods.