From a81530d0d78b253697dd70ec9dc9697060b94035 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Wed, 12 Aug 2026 17:53:02 +0000 Subject: [PATCH] refactor: remove cross-component runtime dependencies --- classes/event/backup_performed.php | 5 +- classes/event/backup_restored.php | 5 +- classes/event/response_answer.php | 3 +- classes/event/service_added.php | 5 +- classes/event/service_deleted.php | 5 +- classes/event/service_updated.php | 5 +- classes/service_edit_form.php | 25 ++++---- classes/service_form.php | 6 +- editservice.php | 6 +- index.php | 24 ++++---- lang/en/local_webhooks.php | 27 +++++++++ lib.php | 42 ++++++++++++++ locallib.php | 2 +- restorebackup.php | 4 +- tests/autonomy_test.php | 91 ++++++++++++++++++++++++++++++ 15 files changed, 204 insertions(+), 51 deletions(-) create mode 100644 tests/autonomy_test.php diff --git a/classes/event/backup_performed.php b/classes/event/backup_performed.php index 7965de7..be0b5f3 100644 --- a/classes/event/backup_performed.php +++ b/classes/event/backup_performed.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class backup_performed extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('create', 'moodle'); + return get_string('create', 'local_webhooks'); } /** @@ -50,7 +49,7 @@ class backup_performed extends base { * @throws \coding_exception */ public function get_description() { - return new lang_string('backup', 'moodle'); + return get_string('backup', 'local_webhooks'); } /** diff --git a/classes/event/backup_restored.php b/classes/event/backup_restored.php index 8cf161c..fe3110d 100644 --- a/classes/event/backup_restored.php +++ b/classes/event/backup_restored.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class backup_restored extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('update', 'moodle'); + return get_string('update', 'local_webhooks'); } /** @@ -50,7 +49,7 @@ class backup_restored extends base { * @throws \coding_exception */ public function get_description() { - return new lang_string('backupfinished', 'moodle'); + return get_string('backupfinished', 'local_webhooks'); } /** diff --git a/classes/event/response_answer.php b/classes/event/response_answer.php index 626d333..80687d2 100644 --- a/classes/event/response_answer.php +++ b/classes/event/response_answer.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class response_answer extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('answer', 'moodle'); + return get_string('answer', 'local_webhooks'); } /** diff --git a/classes/event/service_added.php b/classes/event/service_added.php index fe4d47b..fdc3302 100644 --- a/classes/event/service_added.php +++ b/classes/event/service_added.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class service_added extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('create', 'moodle'); + return get_string('create', 'local_webhooks'); } /** @@ -50,7 +49,7 @@ class service_added extends base { * @throws \coding_exception */ public function get_description() { - return new lang_string('eventwebserviceservicecreated', 'webservice'); + return get_string('eventwebserviceservicecreated', 'local_webhooks'); } /** diff --git a/classes/event/service_deleted.php b/classes/event/service_deleted.php index 66c739c..edbc8bd 100644 --- a/classes/event/service_deleted.php +++ b/classes/event/service_deleted.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class service_deleted extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('deleted', 'moodle'); + return get_string('deleted', 'local_webhooks'); } /** @@ -50,7 +49,7 @@ class service_deleted extends base { * @throws \coding_exception */ public function get_description() { - return new lang_string('eventwebserviceservicedeleted', 'webservice'); + return get_string('eventwebserviceservicedeleted', 'local_webhooks'); } /** diff --git a/classes/event/service_updated.php b/classes/event/service_updated.php index 6b23180..ddff441 100644 --- a/classes/event/service_updated.php +++ b/classes/event/service_updated.php @@ -25,7 +25,6 @@ namespace local_webhooks\event; use core\event\base; -use lang_string; use moodle_url; /** @@ -41,7 +40,7 @@ class service_updated extends base { * @throws \coding_exception */ public static function get_name() { - return new lang_string('update', 'moodle'); + return get_string('update', 'local_webhooks'); } /** @@ -50,7 +49,7 @@ class service_updated extends base { * @throws \coding_exception */ public function get_description() { - return new lang_string('eventwebserviceserviceupdated', 'webservice'); + return get_string('eventwebserviceserviceupdated', 'local_webhooks'); } /** diff --git a/classes/service_edit_form.php b/classes/service_edit_form.php index b4c40da..85cf9e1 100644 --- a/classes/service_edit_form.php +++ b/classes/service_edit_form.php @@ -43,30 +43,30 @@ class service_edit_form extends moodleform { $size = ['size' => 60]; /* Form heading */ - $mform->addElement('header', 'editserviceheader', new lang_string('service', 'webservice')); + $mform->addElement('header', 'editserviceheader', new lang_string('service', 'local_webhooks')); /* Name of the service */ - $mform->addElement('text', 'title', new lang_string('name', 'moodle'), $size); + $mform->addElement('text', 'title', new lang_string('name', 'local_webhooks'), $size); $mform->addRule('title', null, 'required'); $mform->setType('title', PARAM_NOTAGS); /* Callback address */ - $mform->addElement('text', 'url', new lang_string('url', 'moodle'), $size); + $mform->addElement('text', 'url', new lang_string('url', 'local_webhooks'), $size); $mform->addRule('url', null, 'required'); $mform->setType('url', PARAM_URL); /* Enabling the service */ - $mform->addElement('advcheckbox', 'enable', new lang_string('enable', 'moodle')); + $mform->addElement('advcheckbox', 'enable', new lang_string('enable', 'local_webhooks')); $mform->setType('enable', PARAM_BOOL); $mform->setDefault('enable', 1); $mform->setAdvanced('enable'); /* Token */ - $mform->addElement('text', 'token', new lang_string('token', 'webservice'), $size); + $mform->addElement('text', 'token', new lang_string('token', 'local_webhooks'), $size); $mform->setType('token', PARAM_NOTAGS); /* Additional information */ - $mform->addElement('text', 'other', new lang_string('sourceext', 'plugin'), $size); + $mform->addElement('text', 'other', new lang_string('sourceext', 'local_webhooks'), $size); $mform->setType('other', PARAM_NOTAGS); $mform->setAdvanced('other'); @@ -76,21 +76,20 @@ class service_edit_form extends moodleform { 'x-www-form-urlencoded' => 'application/x-www-form-urlencoded', ]; - $mform->addElement('select', 'type', 'Content type', $contenttype); + $mform->addElement('select', 'type', new lang_string('contenttype', 'local_webhooks'), $contenttype); $mform->setAdvanced('type'); /* Form heading */ - $mform->addElement('header', 'editserviceheaderevent', new lang_string('edulevel', 'moodle')); + $mform->addElement('header', 'editserviceheaderevent', new lang_string('edulevel', 'local_webhooks')); /* List of events */ - $eventlist = report_eventlist_list_generator::get_all_events_list(); $events = []; /* Formation of the list of elements */ - foreach ($eventlist as $event) { - /* Escaping event names */ - $eventname = base64_encode($event['eventname']); - $events[$event['component']][] =& $mform->createElement('checkbox', $eventname, $event['eventname']); + foreach (local_webhooks_get_event_choices() as $component => $choices) { + foreach ($choices as $key => $eventname) { + $events[$component][] =& $mform->createElement('checkbox', $key, $eventname); + } } /* Displays groups of items */ diff --git a/classes/service_form.php b/classes/service_form.php index 290f156..f8751e4 100644 --- a/classes/service_form.php +++ b/classes/service_form.php @@ -42,13 +42,13 @@ class service_backup_form extends moodleform { $mform =& $this->_form; /* Form heading */ - $mform->addElement('header', 'editserviceheader', new lang_string('restore', 'moodle')); + $mform->addElement('header', 'editserviceheader', new lang_string('restore', 'local_webhooks')); /* Download the file */ - $mform->addElement('filepicker', 'backupfile', new lang_string('file', 'moodle')); + $mform->addElement('filepicker', 'backupfile', new lang_string('file', 'local_webhooks')); $mform->addRule('backupfile', null, 'required'); /* Control Panel */ - $this->add_action_buttons(true, new lang_string('restore', 'moodle')); + $this->add_action_buttons(true, new lang_string('restore', 'local_webhooks')); } } diff --git a/editservice.php b/editservice.php index a1895ba..26635cf 100644 --- a/editservice.php +++ b/editservice.php @@ -85,15 +85,15 @@ if (!empty($data = $mform->get_data())) { if ($editing) { $data->id = $serviceid; local_webhooks_update_record($data, false); - redirect($managerservice, new lang_string('eventwebserviceserviceupdated', 'webservice')); + redirect($managerservice, new lang_string('eventwebserviceserviceupdated', 'local_webhooks')); } else { local_webhooks_update_record($data); - redirect($managerservice, new lang_string('eventwebserviceservicecreated', 'webservice')); + redirect($managerservice, new lang_string('eventwebserviceservicecreated', 'local_webhooks')); } } /* The page title */ -$titlepage = new lang_string('externalservice', 'webservice'); +$titlepage = new lang_string('externalservice', 'local_webhooks'); $PAGE->navbar->add($titlepage); $PAGE->set_heading($titlepage); $PAGE->set_title($titlepage); diff --git a/index.php b/index.php index 6a4c4fe..75d3f02 100644 --- a/index.php +++ b/index.php @@ -46,7 +46,7 @@ $context = context_system::instance(); /* Delete the service */ if ((bool) $deleteid) { local_webhooks_remove_record($deleteid); - redirect($PAGE->url, new lang_string('eventwebserviceservicedeleted', 'webservice')); + redirect($PAGE->url, new lang_string('eventwebserviceservicedeleted', 'local_webhooks')); } /* Retrieving a list of services */ @@ -66,7 +66,7 @@ if ((bool) $hideshowid) { if (!empty($callback)) { $callback->enable = !(bool) $callback->enable; local_webhooks_update_record($callback, false); - redirect($PAGE->url, new lang_string('eventwebserviceserviceupdated', 'webservice')); + redirect($PAGE->url, new lang_string('eventwebserviceserviceupdated', 'local_webhooks')); } } @@ -90,9 +90,9 @@ $table->define_columns( $table->define_headers( [ - new lang_string('name', 'moodle'), - new lang_string('url', 'moodle'), - new lang_string('actions', 'moodle'), + new lang_string('name', 'local_webhooks'), + new lang_string('url', 'local_webhooks'), + new lang_string('actions', 'local_webhooks'), ] ); @@ -106,10 +106,10 @@ foreach ($callbacks as $callback) { /* Defining service status */ $hideshowicon = 't/show'; - $hideshowstring = new lang_string('enable', 'moodle'); + $hideshowstring = new lang_string('enable', 'local_webhooks'); if ((bool) $callback->enable) { $hideshowicon = 't/hide'; - $hideshowstring = new lang_string('disable', 'moodle'); + $hideshowstring = new lang_string('disable', 'local_webhooks'); } /* Link to enable / disable the service */ @@ -118,11 +118,11 @@ foreach ($callbacks as $callback) { /* Link for editing */ $editlink = new moodle_url($editservice, ['serviceid' => $callback->id]); - $edititem = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', new lang_string('edit', 'moodle'))); + $edititem = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', new lang_string('edit', 'local_webhooks'))); /* Link to remove */ $deletelink = new moodle_url($managerservice, ['deleteid' => $callback->id]); - $deleteitem = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', new lang_string('delete', 'moodle'))); + $deleteitem = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', new lang_string('delete', 'local_webhooks'))); /* Adding data to the table */ $table->add_data([$titlecallback, $urlcallback, $hideshowitem . $edititem . $deleteitem]); @@ -133,14 +133,14 @@ $table->print_html(); /* Add service button */ $addserviceurl = new moodle_url($editservice); -echo $OUTPUT->single_button($addserviceurl, new lang_string('addaservice', 'webservice'), 'get'); +echo $OUTPUT->single_button($addserviceurl, new lang_string('addaservice', 'local_webhooks'), 'get'); /* Button to get a backup */ $backupurl = new moodle_url($managerservice, ['getbackup' => true]); -echo $OUTPUT->single_button($backupurl, new lang_string('backup', 'moodle'), 'get'); +echo $OUTPUT->single_button($backupurl, new lang_string('backup', 'local_webhooks'), 'get'); /* Button for restoring settings */ $restorebackupurl = new moodle_url($restorebackup); -echo $OUTPUT->single_button($restorebackupurl, new lang_string('restore', 'moodle'), 'get'); +echo $OUTPUT->single_button($restorebackupurl, new lang_string('restore', 'local_webhooks'), 'get'); echo $OUTPUT->footer(); diff --git a/lang/en/local_webhooks.php b/lang/en/local_webhooks.php index 6ce5319..2fbca8f 100644 --- a/lang/en/local_webhooks.php +++ b/lang/en/local_webhooks.php @@ -22,5 +22,32 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['actions'] = 'Actions'; +$string['addaservice'] = 'Add service'; +$string['answer'] = 'Answer'; +$string['backup'] = 'Backup'; +$string['backupfinished'] = 'Backup completed successfully'; +$string['contenttype'] = 'Content type'; +$string['create'] = 'Create'; +$string['delete'] = 'Delete'; +$string['deleted'] = 'Deleted'; +$string['disable'] = 'Disable'; +$string['edit'] = 'Edit'; +$string['edulevel'] = 'All events'; +$string['enable'] = 'Enable'; +$string['errorsendingrequest'] = 'Error sending request'; +$string['eventwebserviceservicecreated'] = 'Web service created'; +$string['eventwebserviceservicedeleted'] = 'Web service deleted'; +$string['eventwebserviceserviceupdated'] = 'Web service updated'; +$string['externalservice'] = 'External service'; +$string['file'] = 'File'; +$string['name'] = 'Name'; $string['pluginname'] = 'WebHooks'; $string['privacy:metadata'] = 'WebHooks does not store any personal data.'; +$string['restore'] = 'Restore'; +$string['restorefinished'] = 'Restore completed successfully'; +$string['service'] = 'Service'; +$string['sourceext'] = 'Additional'; +$string['token'] = 'Token'; +$string['update'] = 'Update'; +$string['url'] = 'URL'; diff --git a/lib.php b/lib.php index f43da7b..9ed52aa 100644 --- a/lib.php +++ b/lib.php @@ -26,6 +26,48 @@ defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/locallib.php'); +/** + * Returns available event classes grouped by component. + * + * @return array + */ +function local_webhooks_get_event_choices() { + global $CFG; + + $choices = []; + $debug = $CFG->debug; + + // Deprecated core events emit debugging while loading; mirror the core tool_monitor workaround. + try { + $CFG->debug = DEBUG_NONE; + $classes = core_component::get_component_classes_in_namespace(null, 'event'); + } finally { + $CFG->debug = $debug; + } + + ksort($classes); + foreach (array_keys($classes) as $classname) { + if ( + $classname === \core\event\unknown_logged::class + || !is_subclass_of($classname, \core\event\base::class) + || $classname::is_deprecated() + ) { + continue; + } + + $reflection = new ReflectionClass($classname); + if ($reflection->isAbstract()) { + continue; + } + + $eventname = '\\' . ltrim($classname, '\\'); + $component = core_component::get_component_from_classname($classname); + $choices[$component][base64_encode($eventname)] = $eventname; + } + + return $choices; +} + /** * Getting a list of all services. * diff --git a/locallib.php b/locallib.php index 9998465..260884a 100644 --- a/locallib.php +++ b/locallib.php @@ -79,7 +79,7 @@ class local_webhooks_events { public static function response_answer($objectid = 0, array $response = []) { $context = context_system::instance(); - $status = 'Error sending request'; + $status = get_string('errorsendingrequest', 'local_webhooks'); if (!empty($response['HTTP/1.1'])) { $status = $response['HTTP/1.1']; } diff --git a/restorebackup.php b/restorebackup.php index da855cb..5c15f8e 100644 --- a/restorebackup.php +++ b/restorebackup.php @@ -48,11 +48,11 @@ if ($mform->is_cancelled()) { if (!empty($data = $mform->get_data())) { $content = $mform->get_file_content('backupfile'); local_webhooks_restore_backup($content); - redirect($managerservice, new lang_string('restorefinished', 'moodle')); + redirect($managerservice, new lang_string('restorefinished', 'local_webhooks')); } /* The page title */ -$titlepage = new lang_string('backup', 'moodle'); +$titlepage = new lang_string('backup', 'local_webhooks'); $PAGE->navbar->add($titlepage); $PAGE->set_heading($titlepage); $PAGE->set_title($titlepage); diff --git a/tests/autonomy_test.php b/tests/autonomy_test.php new file mode 100644 index 0000000..5284268 --- /dev/null +++ b/tests/autonomy_test.php @@ -0,0 +1,91 @@ +. + +/** + * Runtime autonomy tests. + * + * @package local_webhooks + * @copyright 2026 "Valentin Popov" + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace local_webhooks; + +/** + * Runtime autonomy tests. + */ +#[\PHPUnit\Framework\Attributes\CoversFunction('local_webhooks_get_event_choices')] +final class autonomy_test extends \advanced_testcase { + /** + * Event choices keep their storage format and custom event names are strings. + */ + public function test_event_contracts(): void { + global $CFG; + + require_once($CFG->dirroot . '/local/webhooks/lib.php'); + require_once($CFG->dirroot . '/local/webhooks/classes/service_edit_form.php'); + + $debugsettings = [$CFG->debug, $CFG->debugdisplay, $CFG->debugdeveloper]; + $choices = \local_webhooks_get_event_choices(); + $this->assertNotEmpty($choices); + $this->assertSame($debugsettings, [$CFG->debug, $CFG->debugdisplay, $CFG->debugdeveloper]); + + foreach ($choices as $component => $events) { + foreach ($events as $key => $eventname) { + $classname = ltrim($eventname, '\\'); + + $this->assertSame(base64_encode($eventname), $key); + $this->assertSame($component, \core_component::get_component_from_classname($classname)); + $this->assertTrue(is_subclass_of($classname, \core\event\base::class)); + $this->assertFalse((new \ReflectionClass($classname))->isAbstract()); + $this->assertFalse($classname::is_deprecated()); + } + } + + $coreevent = '\\' . \core\event\user_created::class; + $localevent = '\\' . \local_webhooks\event\service_added::class; + $unknown = '\\' . \core\event\unknown_logged::class; + $deprecated = '\\' . \core\event\role_capabilities_updated::class; + + $this->assertSame($coreevent, $choices['core'][base64_encode($coreevent)]); + $this->assertSame($localevent, $choices['local_webhooks'][base64_encode($localevent)]); + $this->assertArrayNotHasKey(base64_encode($unknown), $choices['core']); + $this->assertArrayNotHasKey(base64_encode($deprecated), $choices['core']); + + $events = [ + \local_webhooks\event\backup_performed::class => 'create', + \local_webhooks\event\backup_restored::class => 'update', + \local_webhooks\event\response_answer::class => 'answer', + \local_webhooks\event\service_added::class => 'create', + \local_webhooks\event\service_deleted::class => 'deleted', + \local_webhooks\event\service_updated::class => 'update', + ]; + + foreach ($events as $event => $stringkey) { + $name = $event::get_name(); + $this->assertIsString($name); + $this->assertNotSame('', trim($name)); + $this->assertSame(get_string($stringkey, 'local_webhooks'), $name); + } + + $this->assertFalse(class_exists('report_eventlist_list_generator', false)); + $form = new \service_edit_form(new \moodle_url('/local/webhooks/editservice.php')); + $html = $form->render(); + $this->assertStringContainsString($coreevent, $html); + $this->assertStringContainsString($localevent, $html); + $this->assertFalse(class_exists('report_eventlist_list_generator', false)); + } +}