diff --git a/admin/tool/mobile/db/hooks.php b/admin/tool/mobile/db/hooks.php index 91b54ffc7a5..a0ec1affd99 100644 --- a/admin/tool/mobile/db/hooks.php +++ b/admin/tool/mobile/db/hooks.php @@ -26,8 +26,8 @@ defined('MOODLE_INTERNAL') || die(); $callbacks = [ [ - 'hook' => core\hook\output\before_standard_head_html_generation::class, - 'callback' => 'tool_mobile\local\hook\output\before_standard_head_html_generation::callback', + 'hook' => \core\hook\output\before_standard_head_html_generation::class, + 'callback' => [\tool_mobile\local\hooks\output\before_standard_head_html_generation::class, 'callback'], 'priority' => 0, ], ]; diff --git a/lib/classes/hook/manager.php b/lib/classes/hook/manager.php index e793c5810e6..68475fa6707 100644 --- a/lib/classes/hook/manager.php +++ b/lib/classes/hook/manager.php @@ -546,6 +546,13 @@ final class manager implements return null; } $classmethod = $callback['callback']; + if (is_array($classmethod)) { + if (count($classmethod) !== 2) { + debugging("Hook callback definition contains invalid 'callback' array in '$component'", DEBUG_DEVELOPER); + return null; + } + $classmethod = implode('::', $classmethod); + } if (!is_string($classmethod)) { debugging("Hook callback definition contains invalid 'callback' string in '$component'", DEBUG_DEVELOPER); return null; diff --git a/lib/tests/fixtures/hook/hooks1_valid.php b/lib/tests/fixtures/hook/hooks1_valid.php index 78266ac4890..4559902229f 100644 --- a/lib/tests/fixtures/hook/hooks1_valid.php +++ b/lib/tests/fixtures/hook/hooks1_valid.php @@ -28,6 +28,6 @@ defined('MOODLE_INTERNAL') || die(); $callbacks = [ [ 'hook' => 'test_plugin\\hook\\hook', - 'callback' => 'test_plugin\\callbacks::test1', + 'callback' => [\test_plugin\callbacks::class, 'test1'], ], ]; diff --git a/lib/tests/hook/manager_test.php b/lib/tests/hook/manager_test.php index e6f2674cd2a..77a3f55033b 100644 --- a/lib/tests/hook/manager_test.php +++ b/lib/tests/hook/manager_test.php @@ -19,19 +19,17 @@ namespace core\hook; /** * Hooks tests. * - * @coversDefaultClass \core\hook\manager - * * @package core * @author Petr Skoda * @copyright 2022 Open LMS * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \core\hook\manager */ -class manager_test extends \advanced_testcase { +final class manager_test extends \advanced_testcase { /** * Test public factory method to get hook manager. - * @covers ::get_instance */ - public function test_get_instance() { + public function test_get_instance(): void { $manager = manager::get_instance(); $this->assertInstanceOf(manager::class, $manager); @@ -40,9 +38,8 @@ class manager_test extends \advanced_testcase { /** * Test getting of manager test instance. - * @covers ::phpunit_get_instance */ - public function test_phpunit_get_instance() { + public function test_phpunit_get_instance(): void { $testmanager = manager::phpunit_get_instance([]); $this->assertSame([], $testmanager->get_hooks_with_callbacks()); @@ -58,13 +55,8 @@ class manager_test extends \advanced_testcase { /** * Test loading and parsing of callbacks from files. - * - * @covers ::get_callbacks_for_hook - * @covers ::get_hooks_with_callbacks - * @covers ::load_callbacks - * @covers ::add_component_callbacks */ - public function test_callbacks() { + public function test_callbacks(): void { $componentfiles = [ 'test_plugin1' => __DIR__ . '/../fixtures/hook/hooks1_valid.php', 'test_plugin2' => __DIR__ . '/../fixtures/hook/hooks2_valid.php', @@ -94,18 +86,23 @@ class manager_test extends \advanced_testcase { $this->assertSame([], $testmanager->get_hooks_with_callbacks()); $debuggings = $this->getDebuggingMessages(); $this->resetDebugging(); - $this->assertSame('Hook callback definition requires \'hook\' name in \'test_plugin1\'', - $debuggings[0]->message); - $this->assertSame('Hook callback definition requires \'callback\' callable in \'test_plugin1\'', - $debuggings[1]->message); - $this->assertSame('Hook callback definition contains invalid \'callback\' static class method string in \'test_plugin1\'', - $debuggings[2]->message); + $this->assertSame( + 'Hook callback definition requires \'hook\' name in \'test_plugin1\'', + $debuggings[0]->message + ); + $this->assertSame( + 'Hook callback definition requires \'callback\' callable in \'test_plugin1\'', + $debuggings[1]->message + ); + $this->assertSame( + 'Hook callback definition contains invalid \'callback\' static class method string in \'test_plugin1\'', + $debuggings[2]->message + ); $this->assertCount(3, $debuggings); } /** * Test hook dispatching, that is callback execution. - * @covers ::dispatch */ public function test_dispatch(): void { require_once(__DIR__ . '/../fixtures/hook/hook.php'); @@ -127,7 +124,6 @@ class manager_test extends \advanced_testcase { /** * Test hook dispatching, that is callback execution. - * @covers ::dispatch */ public function test_dispatch_with_exception(): void { require_once(__DIR__ . '/../fixtures/hook/hook.php'); @@ -149,7 +145,6 @@ class manager_test extends \advanced_testcase { /** * Test hook dispatching, that is callback execution. - * @covers ::dispatch */ public function test_dispatch_with_invalid(): void { // Missing callbacks is ignored. @@ -171,9 +166,8 @@ class manager_test extends \advanced_testcase { /** * Test stoppping of hook dispatching. - * @covers ::dispatch */ - public function test_dispatch_stoppable() { + public function test_dispatch_stoppable(): void { require_once(__DIR__ . '/../fixtures/hook/stoppablehook.php'); require_once(__DIR__ . '/../fixtures/hook/callbacks.php'); @@ -193,10 +187,8 @@ class manager_test extends \advanced_testcase { /** * Tests callbacks can be overridden via CFG settings. - * @covers ::load_callbacks - * @covers ::dispatch */ - public function test_callback_overriding() { + public function test_callback_overriding(): void { global $CFG; $this->resetAfterTest(); @@ -224,8 +216,8 @@ class manager_test extends \advanced_testcase { $CFG->hooks_callback_overrides = [ 'test_plugin\\hook\\hook' => [ - 'test_plugin\\callbacks::test2' => ['priority' => 33] - ] + 'test_plugin\\callbacks::test2' => ['priority' => 33], + ], ]; $testmanager = manager::phpunit_get_instance($componentfiles); @@ -249,8 +241,8 @@ class manager_test extends \advanced_testcase { $CFG->hooks_callback_overrides = [ 'test_plugin\\hook\\hook' => [ - 'test_plugin\\callbacks::test2' => ['priority' => 33, 'disabled' => true] - ] + 'test_plugin\\callbacks::test2' => ['priority' => 33, 'disabled' => true], + ], ]; $testmanager = manager::phpunit_get_instance($componentfiles); $this->assertSame(['test_plugin\\hook\\hook'], $testmanager->get_hooks_with_callbacks()); @@ -262,8 +254,7 @@ class manager_test extends \advanced_testcase { 'component' => 'test_plugin1', 'disabled' => false, 'priority' => 100, - ], - $callbacks[0]); + ], $callbacks[0]); $this->assertSame([ 'callback' => 'test_plugin\\callbacks::test2', 'component' => 'test_plugin2', @@ -275,7 +266,7 @@ class manager_test extends \advanced_testcase { $CFG->hooks_callback_overrides = [ 'test_plugin\\hook\\hook' => [ 'test_plugin\\callbacks::test2' => ['disabled' => true], - ] + ], ]; $testmanager = manager::phpunit_get_instance($componentfiles); $this->assertSame(['test_plugin\\hook\\hook'], $testmanager->get_hooks_with_callbacks());