diff --git a/core/core.api.php b/core/core.api.php index 9ecb878dfc3149606e2320eb9e878961f8271fab..0500a3c58aecebc87336db728c2818d51135bc86 100644 --- a/core/core.api.php +++ b/core/core.api.php @@ -1633,13 +1633,13 @@ * - On a method, use the attribute with the hook name: * @code * #[Hook('user_cancel')] - * public method userCancel(...) + * public function userCancel(...) {} * @endcode * - On a class, specify the method name as well as the hook name: * @code * #[Hook('user_cancel', method: 'userCancel')] * class Hooks { - * method userCancel(...) {} + * public function userCancel(...) {} * } * @endcode * - On a class with an __invoke method, which is taken to be the hook @@ -1647,7 +1647,7 @@ * @code * #[Hook('user_cancel')] * class Hooks { - * method __invoke(...) {} + * public function __invoke(...) {} * } * @endcode * diff --git a/core/lib/Drupal/Core/Hook/Attribute/Hook.php b/core/lib/Drupal/Core/Hook/Attribute/Hook.php index 74ad0d77ce4ade61433873eaf349028eabc4f5a4..1b220577a13130d6b8a790a5b1f41ecaebb60fd7 100644 --- a/core/lib/Drupal/Core/Hook/Attribute/Hook.php +++ b/core/lib/Drupal/Core/Hook/Attribute/Hook.php @@ -12,13 +12,13 @@ * - On a method, use this attribute with the hook name: * @code * #[Hook('user_cancel')] - * public method userCancel(...) + * public function userCancel(...) {} * @endcode * - On a class, specifying the method name: * @code * #[Hook('user_cancel', method: 'userCancel')] * class Hooks { - * method userCancel(...) {} + * public function userCancel(...) {} * } * @endcode * - On a class with an __invoke method, which is taken to be the hook @@ -26,7 +26,7 @@ * @code * #[Hook('user_cancel')] * class Hooks { - * method __invoke(...) {} + * public function __invoke(...) {} * } * @endcode * diff --git a/core/modules/system/tests/modules/hook_collector_hook_attribute/hook_collector_hook_attribute.info.yml b/core/modules/system/tests/modules/hook_collector_hook_attribute/hook_collector_hook_attribute.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..73e43bcc0cf24ca0441e27e50605b7402ccc4872 --- /dev/null +++ b/core/modules/system/tests/modules/hook_collector_hook_attribute/hook_collector_hook_attribute.info.yml @@ -0,0 +1,5 @@ +name: 'Test Hook attribute' +type: module +description: 'Test Hook attribute with named arguments, and class with invoke method' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeInvokeHook.php b/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeInvokeHook.php new file mode 100644 index 0000000000000000000000000000000000000000..8d81c09d8ebc1ed6d952fd300a86be284191e154 --- /dev/null +++ b/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeInvokeHook.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\hook_collector_hook_attribute\Hook; + +use Drupal\Core\Hook\Attribute\Hook; + +/** + * Test Hook attribute named arguments. + */ +#[Hook('cache_flush')] +class HookAttributeInvokeHook { + + /** + * Implements hook_cache_flush(). + */ + public function __invoke(): void { + // Set a global value we can check in test code. + $GLOBALS['hook_invoke_method'] = 'hook_invoke_method'; + } + +} diff --git a/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeNamedArgumentsHook.php b/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeNamedArgumentsHook.php new file mode 100644 index 0000000000000000000000000000000000000000..78affab8f54a2449da5e853a8e9295630094963f --- /dev/null +++ b/core/modules/system/tests/modules/hook_collector_hook_attribute/src/Hook/HookAttributeNamedArgumentsHook.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\hook_collector_hook_attribute\Hook; + +use Drupal\Core\Hook\Attribute\Hook; + +/** + * Test Hook attribute named arguments. + */ +#[Hook(hook: 'cache_flush', method: 'flush')] +class HookAttributeNamedArgumentsHook { + + /** + * Implements hook_cache_flush(). + */ + public function flush(): void { + // Set a global value we can check in test code. + $GLOBALS['hook_named_arguments'] = 'hook_named_arguments'; + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Hook/HookCollectorPassTest.php b/core/tests/Drupal/KernelTests/Core/Hook/HookCollectorPassTest.php index 12ca7ce21bba37410539d922f452d6d4cfa7f453..4156481d3b924a88d8fcf1b0953b80e1669b66c2 100644 --- a/core/tests/Drupal/KernelTests/Core/Hook/HookCollectorPassTest.php +++ b/core/tests/Drupal/KernelTests/Core/Hook/HookCollectorPassTest.php @@ -124,4 +124,17 @@ public function testProceduralHooksSkippedWhenConfigured(): void { } + /** + * Test Hook attribute with named arguments, and class with invoke method. + */ + public function testHookAttribute(): void { + $module_installer = $this->container->get('module_installer'); + $this->assertTrue($module_installer->install(['hook_collector_hook_attribute'])); + $this->assertFalse(isset($GLOBALS['hook_named_arguments'])); + $this->assertFalse(isset($GLOBALS['hook_invoke_method'])); + drupal_flush_all_caches(); + $this->assertTrue(isset($GLOBALS['hook_named_arguments'])); + $this->assertTrue(isset($GLOBALS['hook_invoke_method'])); + } + } diff --git a/core/tests/Drupal/Tests/Core/Hook/HookCollectorPassTest.php b/core/tests/Drupal/Tests/Core/Hook/HookCollectorPassTest.php index c4559d290f39dc48d9a523234606978f73655490..546b489cb4c5b6dda743c22dd613d401251828f9 100644 --- a/core/tests/Drupal/Tests/Core/Hook/HookCollectorPassTest.php +++ b/core/tests/Drupal/Tests/Core/Hook/HookCollectorPassTest.php @@ -93,14 +93,7 @@ public function testGetHookAttributesInClass(): void { $getHookAttributesInClass = fn ($class) => $this->getHookAttributesInClass($class); $p = new HookCollectorPass(); $getHookAttributesInClass = $getHookAttributesInClass->bindTo($p, $p); - $x = new class { - - #[Hook('install')] - function foo(): void {} - }; - $this->expectException(\LogicException::class); - $hooks = $getHookAttributesInClass(get_class($x)); $x = new class { #[Hook('foo')] @@ -111,6 +104,16 @@ function foo(): void {} $hook = reset($hooks); $this->assertInstanceOf(Hook::class, $hook); $this->assertSame('foo', $hook->hook); + + $x = new class { + + #[Hook('install')] + function foo(): void {} + + }; + $this->expectException(\LogicException::class); + // This will throw exception, and stop code execution. + $getHookAttributesInClass(get_class($x)); } }