Skip to content

Commit

Permalink
Merge branch 'MDL-80099_main' of https://github.com/marxjohnson/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyatregubov committed Mar 22, 2024
2 parents 7e9a206 + ee952d6 commit 9f10899
Show file tree
Hide file tree
Showing 26 changed files with 853 additions and 38 deletions.
37 changes: 35 additions & 2 deletions lib/classes/hook/manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,34 @@ public static function get_instance(): manager {
* Factory method for testing of hook manager in PHPUnit tests.
*
* @param array $componentfiles list of hook callback files for each component.
* @param bool $persist If true, the test instance will be stored in self::$instance. Be sure to call $this->resetAfterTest()
* in your test if you use this.
* @return self
*/
public static function phpunit_get_instance(array $componentfiles): manager {
public static function phpunit_get_instance(array $componentfiles, bool $persist = false): manager {
if (!PHPUNIT_TEST) {
throw new \coding_exception('Invalid call of manager::phpunit_get_instance() outside of tests');
}
$instance = new self();
$instance->load_callbacks($componentfiles);
if ($persist) {
self::$instance = $instance;
}
return $instance;
}

/**
* Reset self::$instance so that future calls to ::get_instance() will return a regular instance.
*
* @return void
*/
public static function phpunit_reset_instance(): void {
if (!PHPUNIT_TEST) {
throw new \coding_exception('Invalid call of manager::phpunit_reset_instance() outside of tests');
}
self::$instance = null;
}

/**
* Override hook callbacks for testing purposes.
*
Expand Down Expand Up @@ -576,9 +593,25 @@ private function normalise_callback(string $component, array $callback): ?string
*
* @param string $plugincallback short callback name without the component prefix
* @return bool
* @deprecated in favour of get_hooks_deprecating_plugin_callback since Moodle 4.4.
* @todo Remove in Moodle 4.8 (MDL-80327).
*/
public function is_deprecated_plugin_callback(string $plugincallback): bool {
return isset($this->alldeprecations[$plugincallback]);
debugging(
'is_deprecated_plugin_callback method is deprecated, use get_hooks_deprecating_plugin_callback instead.',
DEBUG_DEVELOPER
);
return (bool)$this->get_hooks_deprecating_plugin_callback($plugincallback);
}

/**
* If the plugin callback from lib.php is deprecated by any hooks, return the hooks' classnames.
*
* @param string $plugincallback short callback name without the component prefix
* @return ?array
*/
public function get_hooks_deprecating_plugin_callback(string $plugincallback): ?array {
return $this->alldeprecations[$plugincallback] ?? null;
}

/**
Expand Down
37 changes: 31 additions & 6 deletions lib/moodlelib.php
Original file line number Diff line number Diff line change
Expand Up @@ -7453,13 +7453,17 @@ function get_plugins_with_function($function, $file = 'lib.php', $include = true
foreach ($pluginfunctions as $plugintype => $plugins) {
foreach ($plugins as $plugin => $unusedfunction) {
$component = $plugintype . '_' . $plugin;
if (\core\hook\manager::get_instance()->is_deprecated_plugin_callback($plugincallback)) {
if ($hooks = \core\hook\manager::get_instance()->get_hooks_deprecating_plugin_callback($plugincallback)) {
if (\core\hook\manager::get_instance()->is_deprecating_hook_present($component, $plugincallback)) {
// Ignore the old callback, it is there only for older Moodle versions.
unset($pluginfunctions[$plugintype][$plugin]);
} else {
debugging("Callback $plugincallback in $component component should be migrated to new hook callback",
DEBUG_DEVELOPER);
$hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of ' . implode(', ', $hooks);
debugging(
"Callback $plugincallback in $component component should be migrated to new " .
"hook callback for $hookmessage",
DEBUG_DEVELOPER
);
}
}
}
Expand Down Expand Up @@ -7688,13 +7692,15 @@ function component_callback($component, $function, array $params = array(), $def

if ($functionname) {
if ($migratedtohook) {
if (\core\hook\manager::get_instance()->is_deprecated_plugin_callback($function)) {
if ($hooks = \core\hook\manager::get_instance()->get_hooks_deprecating_plugin_callback($function)) {
if (\core\hook\manager::get_instance()->is_deprecating_hook_present($component, $function)) {
// Do not call the old lib.php callback,
// it is there for compatibility with older Moodle versions only.
return null;
} else {
debugging("Callback $function in $component component should be migrated to new hook callback",
$hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of ' . implode(', ', $hooks);
debugging(
"Callback $function in $component component should be migrated to new hook callback for $hookmessage",
DEBUG_DEVELOPER);
}
}
Expand Down Expand Up @@ -7769,9 +7775,10 @@ function component_callback_exists($component, $function) {
* @param string $methodname The name of the staticically defined method on the class.
* @param array $params The arguments to pass into the method.
* @param mixed $default The default value.
* @param bool $migratedtohook True if the callback has been migrated to a hook.
* @return mixed The return value.
*/
function component_class_callback($classname, $methodname, array $params, $default = null) {
function component_class_callback($classname, $methodname, array $params, $default = null, bool $migratedtohook = false) {
if (!class_exists($classname)) {
return $default;
}
Expand All @@ -7781,6 +7788,24 @@ function component_class_callback($classname, $methodname, array $params, $defau
}

$fullfunction = $classname . '::' . $methodname;

if ($migratedtohook) {
$functionparts = explode('\\', trim($fullfunction, '\\'));
$component = $functionparts[0];
$callback = end($functionparts);
if ($hooks = \core\hook\manager::get_instance()->get_hooks_deprecating_plugin_callback($callback)) {
if (\core\hook\manager::get_instance()->is_deprecating_hook_present($component, $callback)) {
// Do not call the old class callback,
// it is there for compatibility with older Moodle versions only.
return null;
} else {
$hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of ' . implode(', ', $hooks);
debugging("Callback $callback in $component component should be migrated to new hook callback for $hookmessage",
DEBUG_DEVELOPER);
}
}
}

$result = call_user_func_array($fullfunction, $params);

if (null === $result) {
Expand Down
3 changes: 3 additions & 0 deletions lib/phpunit/classes/util.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public static function reset_all_data($detectchanges = false) {
// Stop all hook redirections.
\core\hook\manager::get_instance()->phpunit_stop_redirections();

// Reset the hook manager instance.
\core\hook\manager::phpunit_reset_instance();

// Stop any message redirection.
self::stop_message_redirection();

Expand Down
44 changes: 44 additions & 0 deletions lib/tests/fixtures/fakeplugins/hooktest/classes/callbacks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace fake_hooktest;

/**
* Class callback container for fake_hooktest
*
* @package core
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class callbacks {
/**
* Test callback that is not replaced by a hook.
*
* @return string
*/
public static function current_class_callback(): string {
return 'Called current class callback';
}

/**
* Test callback that is replaced by a hook.
*
* @return string
*/
public static function old_class_callback(): string {
return 'Called deprecated class callback';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace fake_hooktest\hook;

/**
* Fixture for testing of hooks.
*
* @package core
* @author Mark Johnson <[email protected]>
* @copyright 2024 Catalyst IT Europe Ltd.
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class hook_replacing_callback implements
\core\hook\described_hook,
\core\hook\deprecated_callback_replacement {

/**
* Hook description.
*/
public static function get_hook_description(): string {
return 'Test hook replacing a plugin callback function.';
}

/**
* Deprecation info.
*/
public static function get_deprecated_plugin_callbacks(): array {
return ['old_callback'];
}

/**
* List of tags that describe this hook.
*
* @return string[]
*/
public static function get_hook_tags(): array {
return ['test'];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.

namespace fake_hooktest\hook;

use core\attribute;

/**
* Fixture for testing of hooks.
*
* @package core
* @author Mark Johnson <[email protected]>
* @copyright 2024 Catalyst IT Europe Ltd.
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
#[attribute\label('Test hook replacing a class callback.')]
#[attribute\tags('test')]
#[attribute\hook\replaces_callbacks('callbacks::old_class_callback')]
final class hook_replacing_class_callback {
}
44 changes: 44 additions & 0 deletions lib/tests/fixtures/fakeplugins/hooktest/classes/hook_callbacks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace fake_hooktest;

/**
* Hook callbacks
*
* @package core
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class hook_callbacks {
/**
* Test callback which replaces a plugin callback.
*
* @return string
*/
public function component_callback_replacement(): string {
return 'Called component callback replacement';
}

/**
* Test callback which replaced a plugin class callback.
*
* @return string
*/
public function component_class_callback_replacement(): string {
return 'Called component class callback replacement';
}
}
41 changes: 41 additions & 0 deletions lib/tests/fixtures/fakeplugins/hooktest/classes/hooks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace fake_hooktest;

/**
* Hook discovery for fake plugin.
*
* @package core
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class hooks implements \core\hook\discovery_agent {
public static function discover_hooks(): array {
return [
'fake_hooktest\hook\hook_replacing_callback' => [
'class' => 'fake_hooktest\hook\hook_replacing_callback',
'description' => 'Hook replacing callback',
'tags' => ['test'],
],
'fake_hooktest\hook\hook_replacing_class_callback' => [
'class' => 'fake_hooktest\hook\hook_replacing_class_callback',
'description' => 'Hook replacing class callback',
'tags' => ['test'],
],
];
}
}
Loading

0 comments on commit 9f10899

Please sign in to comment.