Skip to content
Snippets Groups Projects
Commit 4eb711e1 authored by dpi's avatar dpi
Browse files

Issue #3293970 by dpi: Single invoke does not work

parent e2beca2c
No related branches found
No related tags found
No related merge requests found
...@@ -64,13 +64,26 @@ final class HuxModuleHandler implements ModuleHandlerInterface { ...@@ -64,13 +64,26 @@ final class HuxModuleHandler implements ModuleHandlerInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function invoke($module, $hook, array $args = []) { public function invoke($module, $hook, array $args = []) {
$original = function (&...$args) use ($module, $hook): mixed {
// If there are Hux implementations, only the last return value
// will be returned.
$return = $this->inner->invoke($module, $hook, $args);
$callback = static function (callable $hookInvoker, string $calledModule) use ($module, $args, &$return): void {
if ($module === $calledModule) {
$return = $hookInvoker(...$args);
}
};
$this->invokeHux($hook, $callback);
return $return;
};
$replacements = $this->getOriginalHookReplacementInvokers($hook); $replacements = $this->getOriginalHookReplacementInvokers($hook);
$replacement = ($replacements[$module] ?? NULL)?->getCallable( $replacement = ($replacements[$module] ?? NULL)?->getCallable($original);
fn (...$args) => $this->inner->invoke($module, $hook, [...$args])
);
return $replacement return $replacement
? $replacement(...$args) ? $replacement(...$args)
: $this->inner->invoke($module, $hook, $args); : $original(...$args);
} }
/** /**
......
...@@ -36,6 +36,19 @@ final class HuxReplacementTestHooks { ...@@ -36,6 +36,19 @@ final class HuxReplacementTestHooks {
return __FUNCTION__ . ' return'; return __FUNCTION__ . ' return';
} }
/**
* Replaces one function and two Hux hooks.
*
* @see \hux_test_test_hook_single_invoke_return()
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn1
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn2
*/
#[ReplaceOriginalHook('test_hook_single_invoke_return', moduleName: 'hux_test', originalInvoker: TRUE)]
public function myReplacementWithOriginalMultipleImplementations(callable $originalInvoker, string $something): mixed {
HuxTestCallTracker::record([__CLASS__, __FUNCTION__, $something]);
return __FUNCTION__ . ' passed down ' . $originalInvoker($something);
}
/** /**
* Replaces multiple hooks. * Replaces multiple hooks.
* *
......
...@@ -62,3 +62,27 @@ function hux_test_original_invoker_attribute_last(): string { ...@@ -62,3 +62,27 @@ function hux_test_original_invoker_attribute_last(): string {
HuxTestCallTracker::record(__FUNCTION__); HuxTestCallTracker::record(__FUNCTION__);
return __FUNCTION__ . ' return'; return __FUNCTION__ . ' return';
} }
/**
* Implements hook_single_invoke().
*/
function hux_test_single_invoke(): string {
HuxTestCallTracker::record(__FUNCTION__);
return __FUNCTION__ . ' return';
}
/**
* Implements hook_test_hook_single_invoke_return().
*/
function hux_test_test_hook_single_invoke_return(): string {
HuxTestCallTracker::record(__FUNCTION__);
return __FUNCTION__ . ' return';
}
/**
* Implements hook_single_invoke_argument_reference().
*/
function hux_test_single_invoke_argument_reference(int &$something): void {
$something++;
HuxTestCallTracker::record([__FUNCTION__, $something]);
}
...@@ -32,6 +32,39 @@ final class HuxTestHooks { ...@@ -32,6 +32,39 @@ final class HuxTestHooks {
return __FUNCTION__ . ' return'; return __FUNCTION__ . ' return';
} }
/**
* Implements test_hook_single_invoke_return().
*
* Tests the return value of using ::invoke with multiple implementations.
*/
#[Hook('test_hook_single_invoke_return')]
public function testHookSingleReturn1(): string {
HuxTestCallTracker::record([__CLASS__, __FUNCTION__]);
return __FUNCTION__ . ' return';
}
/**
* Implements test_hook_single_invoke_return().
*
* Tests the return value of using ::invoke with multiple implementations.
*/
#[Hook('test_hook_single_invoke_return')]
public function testHookSingleReturn2(): string {
HuxTestCallTracker::record([__CLASS__, __FUNCTION__]);
return __FUNCTION__ . ' return';
}
/**
* Implements hook_single_invoke_argument_reference().
*
* Tests arguments are passed by reference.
*/
#[Hook('single_invoke_argument_reference')]
public function testInvokeWithHuxMutatesByReference(int &$something): void {
$something++;
HuxTestCallTracker::record([__CLASS__, __FUNCTION__, $something]);
}
/** /**
* Implements multiple hooks. * Implements multiple hooks.
* *
......
...@@ -74,6 +74,38 @@ final class HuxReplacementTest extends KernelTestBase { ...@@ -74,6 +74,38 @@ final class HuxReplacementTest extends KernelTestBase {
$this->assertEquals('myReplacementWithOriginal return', $result); $this->assertEquals('myReplacementWithOriginal return', $result);
} }
/**
* Tests with the replacement and original invoker.
*
* Tests specifically with ::invoke, with multiple implementations.
*
* @covers ::invoke
* @see \hux_test_test_hook_single_invoke_return()
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn1
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn2
*/
public function testInvokeReplacementWithOriginalInvokerSingleInvokeMultiple(): void {
$this->moduleInstaller()->install(['hux_replacement_test'], TRUE);
$result = $this->moduleHandler()->invoke('hux_test', 'test_hook_single_invoke_return', ['bar']);
$this->assertEquals([
[
'Drupal\hux_replacement_test\HuxReplacementTestHooks',
'myReplacementWithOriginalMultipleImplementations',
'bar',
],
'hux_test_test_hook_single_invoke_return',
[
'Drupal\hux_test\HuxTestHooks',
'testHookSingleReturn1',
],
[
'Drupal\hux_test\HuxTestHooks',
'testHookSingleReturn2',
],
], HuxTestCallTracker::$calls);
$this->assertEquals('myReplacementWithOriginalMultipleImplementations passed down testHookSingleReturn2 return', $result);
}
/** /**
* Tests with the replacement. * Tests with the replacement.
* *
......
...@@ -61,6 +61,71 @@ final class HuxTest extends KernelTestBase { ...@@ -61,6 +61,71 @@ final class HuxTest extends KernelTestBase {
], $result); ], $result);
} }
/**
* Tests single invoke defers to default implementation when no Hux hooks.
*
* @covers ::invoke
* @see \hux_test_single_invoke()
*/
public function testInvokeNoHux(): void {
$result = $this->moduleHandler()->invoke('hux_test', 'single_invoke');
$this->assertEquals([
'hux_test_single_invoke',
], HuxTestCallTracker::$calls);
$this->assertEquals('hux_test_single_invoke return', $result);
}
/**
* Tests single invoke defers to default implementation with Hux hooks.
*
* @covers ::invoke
* @see \hux_test_test_hook_single_invoke_return()
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn1
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn2
*/
public function testInvokeWithHux(): void {
$result = $this->moduleHandler()->invoke('hux_test', 'test_hook_single_invoke_return');
$this->assertEquals([
'hux_test_test_hook_single_invoke_return',
[
'Drupal\hux_test\HuxTestHooks',
'testHookSingleReturn1',
],
[
'Drupal\hux_test\HuxTestHooks',
'testHookSingleReturn2',
],
], HuxTestCallTracker::$calls);
// Only the last invocation return value is returned.
$this->assertEquals('testHookSingleReturn2 return', $result);
}
/**
* Tests single invoke context is mutated and passed by reference.
*
* @covers ::invoke
* @see \hux_test_test_hook_single_invoke_return()
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn1
* @see \Drupal\hux_test\HuxTestHooks::testHookSingleReturn2
*/
public function testInvokeWithHuxMutatesByReference(): void {
$something = 0;
$this->moduleHandler()->invoke('hux_test', 'single_invoke_argument_reference', [&$something]);
$this->assertEquals([
[
'hux_test_single_invoke_argument_reference',
1,
],
[
'Drupal\hux_test\HuxTestHooks',
'testInvokeWithHuxMutatesByReference',
2,
],
], HuxTestCallTracker::$calls);
// Only the last invocation return value is returned.
$this->assertEquals(2, $something);
}
/** /**
* @covers \Drupal\hux\HuxDiscovery::discovery * @covers \Drupal\hux\HuxDiscovery::discovery
* @see \Drupal\hux_test\HuxTestHooks::testHookMultiListener * @see \Drupal\hux_test\HuxTestHooks::testHookMultiListener
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment