diff --git a/classes/local/form/form_step_instance.php b/classes/local/form/form_step_instance.php index 0543b54f..85d36689 100644 --- a/classes/local/form/form_step_instance.php +++ b/classes/local/form/form_step_instance.php @@ -191,8 +191,11 @@ public function definition_after_data() { $mform->setDefault('id', ''); $subpluginname = $this->subpluginname; } - $mform->setDefault('subpluginnamestatic', - get_string('pluginname', 'lifecyclestep_' . $subpluginname)); + + if (isset($this->lib)) { + $mform->setDefault('subpluginnamestatic', $this->lib->get_plugin_description()); + } + $mform->setDefault('subpluginname', $subpluginname); // Setting the default values for the local step settings. diff --git a/classes/local/form/form_trigger_instance.php b/classes/local/form/form_trigger_instance.php index e3d075a3..d7c9834f 100644 --- a/classes/local/form/form_trigger_instance.php +++ b/classes/local/form/form_trigger_instance.php @@ -173,8 +173,11 @@ public function definition_after_data() { $mform->setDefault('id', $this->trigger->id); $mform->setDefault('instancename', $this->trigger->instancename); } - $mform->setDefault('subpluginnamestatic', - get_string('pluginname', 'lifecycletrigger_' . $this->subpluginname)); + + if (isset($this->lib)) { + $mform->setDefault('subpluginnamestatic', $this->lib->get_plugin_description()); + } + $mform->setDefault('subpluginname', $this->subpluginname); // Setting the default values for the local trigger settings. diff --git a/classes/local/manager/lib_manager.php b/classes/local/manager/lib_manager.php index afd381ee..22861672 100644 --- a/classes/local/manager/lib_manager.php +++ b/classes/local/manager/lib_manager.php @@ -102,18 +102,27 @@ public static function get_step_interactionlib($subpluginname) { * @return null|base|libbase */ private static function get_lib($subpluginname, $subplugintype, $libsubtype = '') { + // Plugins defined in subplugins.json file. $triggerlist = \core_component::get_plugin_list('lifecycle' . $subplugintype); - if (!array_key_exists($subpluginname, $triggerlist)) { - return null; - } - $filename = $triggerlist[$subpluginname].'/'.$libsubtype.'lib.php'; - if (file_exists($filename)) { - require_once($filename); - $extendedclass = "tool_lifecycle\\$subplugintype\\$libsubtype$subpluginname"; - if (class_exists($extendedclass)) { - return new $extendedclass(); + if (array_key_exists($subpluginname, $triggerlist)) { + $filename = $triggerlist[$subpluginname].'/'.$libsubtype.'lib.php'; + if (file_exists($filename)) { + require_once($filename); + $extendedclass = "tool_lifecycle\\$subplugintype\\$libsubtype$subpluginname"; + if (class_exists($extendedclass)) { + return new $extendedclass(); + } } } + + // Plugins defined under "lifecycle" name space. + // The base class has already been checked by get_trigger_types or get_steps_types. + $classname = !$libsubtype ? $subplugintype : $libsubtype; + $classname = "$subpluginname\\lifecycle\\$classname"; + if (class_exists($classname)) { + return new $classname(); + } + return null; } } diff --git a/classes/local/manager/step_manager.php b/classes/local/manager/step_manager.php index bfb67d3b..fa26279c 100644 --- a/classes/local/manager/step_manager.php +++ b/classes/local/manager/step_manager.php @@ -239,11 +239,27 @@ public static function get_step_instances_by_subpluginname($subpluginname) { * @throws \coding_exception */ public static function get_step_types() { + // Sub plugins in 'step' folder. $subplugins = \core_component::get_plugin_list('lifecyclestep'); $result = []; foreach (array_keys($subplugins) as $plugin) { $result[$plugin] = get_string('pluginname', 'lifecyclestep_' . $plugin); } + + // Additional sub plugins defined under "lifecycle" name space, ie "local_newstep\lifecycle". + // The class name must be step (step.php) and placed under "classes/lifecycle" folder. + // The name space must be "local_newstep\lifecycle" + // The "local_newstep\lifecycle\step" class must extend the step base classes. + foreach (array_keys(\core_component::get_plugin_types()) as $plugintype) { + $potentialsteps = \core_component::get_plugin_list_with_class($plugintype, 'lifecycle\\step'); + foreach ($potentialsteps as $plugin => $potentialstep) { + // Check if it implements the step base class. + if (is_a($potentialstep, \tool_lifecycle\step\libbase::class, true)) { + $result[$plugin] = get_string('pluginname', $plugin); + } + } + } + return $result; } diff --git a/classes/local/manager/trigger_manager.php b/classes/local/manager/trigger_manager.php index 79d57140..21b96df0 100644 --- a/classes/local/manager/trigger_manager.php +++ b/classes/local/manager/trigger_manager.php @@ -254,6 +254,21 @@ public static function get_trigger_types() { $result[$plugin] = get_string('pluginname', 'lifecycletrigger_' . $plugin); } } + + // Additional sub plugins defined under "lifecycle" name space, ie "local_newtrigger\lifecycle". + // The class name must be trigger (trigger.php) and placed under "classes/lifecycle" folder. + // The name space must be "local_newtrigger\lifecycle" + // The "local_newtrigger\lifecycle\trigger" class must extend the trigger base classes (base_automatic or base_manual). + foreach (array_keys(\core_component::get_plugin_types()) as $plugintype) { + $potentialtriggers = \core_component::get_plugin_list_with_class($plugintype, 'lifecycle\\trigger'); + foreach ($potentialtriggers as $plugin => $potentialtrigger) { + // Check if it implements the trigger base class. + if (is_a($potentialtrigger, \tool_lifecycle\trigger\base::class, true)) { + $result[$plugin] = get_string('pluginname', $plugin); + } + } + } + return $result; } diff --git a/settings.php b/settings.php index f5c3359a..a8891dc5 100644 --- a/settings.php +++ b/settings.php @@ -25,6 +25,9 @@ defined('MOODLE_INTERNAL') || die(); +use tool_lifecycle\local\manager\lib_manager; +use tool_lifecycle\local\manager\step_manager; +use tool_lifecycle\local\manager\trigger_manager; use tool_lifecycle\tabs; // Check for the moodle/site:config permission. @@ -89,5 +92,62 @@ get_string('config_forum_desc', 'tool_lifecycle'), null, PARAM_INT)); + $triggers = core_component::get_plugin_list('lifecycletrigger'); + if ($triggers) { + $settings->add(new admin_setting_heading('lifecycletriggerheader', + get_string('triggers_installed', 'tool_lifecycle'), '')); + foreach ($triggers as $trigger => $path) { + $triggername = html_writer::span(get_string('pluginname', 'lifecycletrigger_' . $trigger), + "font-weight-bold"); + $uninstall = ''; + if ($trigger == 'sitecourse' || $trigger == 'delayedcourses') { + $uninstall = html_writer::span(' Depracated. Will be removed with version 5.0.', 'text-danger'); + } + if ($trigger == 'customfieldsemester') { + $settings->add(new admin_setting_description('lifecycletriggersetting_'.$trigger, + $triggername, + get_string('customfieldsemesterdescription', 'tool_lifecycle'))); + } else { + try { + $plugindescription = get_string('plugindescription', 'lifecycletrigger_' . $trigger); + } catch (Exception $e) { + $plugindescription = ""; + } + $settings->add(new admin_setting_description('lifecycletriggersetting_'.$trigger, + $triggername, + $plugindescription.$uninstall)); + $lib = lib_manager::get_trigger_lib($trigger); + $lib->get_plugin_settings(); + } + } + } else { + $settings->add(new admin_setting_heading('adminsettings_notriggers', + get_string('adminsettings_notriggers', 'tool_lifecycle'), '')); + } + + $steps = core_component::get_plugin_list('lifecyclestep'); + if ($steps) { + $settings->add(new admin_setting_heading('lifecyclestepheader', + get_string('steps_installed', 'tool_lifecycle'), '')); + foreach ($steps as $step => $path) { + $stepname = html_writer::span(get_string('pluginname', 'lifecyclestep_' . $step), + "font-weight-bold"); + try { + $plugindescription = get_string('plugindescription', 'lifecyclestep_' . $step); + } catch (Exception $e) { + $plugindescription = ""; + } + $settings->add(new admin_setting_description('lifecyclestepsetting_'.$step, + $stepname, + $plugindescription)); + $lib = lib_manager::get_step_lib($step); + $lib->get_plugin_settings(); + } + } else { + $settings->add(new admin_setting_heading('adminsettings_nosteps', + get_string('adminsettings_nosteps', 'tool_lifecycle'), '')); + } + $settings->add(new admin_setting_description('spacer', "", " ")); + $ADMIN->add('tools', $settings); } diff --git a/step/lib.php b/step/lib.php index f8bc421a..92aaeb3d 100644 --- a/step/lib.php +++ b/step/lib.php @@ -190,6 +190,40 @@ public function get_icon() { public function is_stoppable() { return false; } + + /** + * Define name of the step. + * Allow subplugins to have custom name. + * + * @return string name of the trigger. + */ + public function get_plugin_name() { + return get_string("pluginname", "lifecyclestep_" . $this->get_subpluginname()); + } + + /** + * Define description of the step. + * Allow subplugins to have custom description. + * + * @return string description of the trigger. + */ + public function get_plugin_description() { + return get_string("plugindescription", "lifecyclestep_" . $this->get_subpluginname()); + } + + /** + * Returns the settings of the step. + * + * @return void + */ + public function get_plugin_settings() { + $step = $this->get_subpluginname(); + $file = __DIR__ . "/$step/settings.php"; + + if (file_exists($file)) { + include($file); + } + } } /** diff --git a/subplugins.php b/subplugins.php index aba509b8..0b31a8dd 100644 --- a/subplugins.php +++ b/subplugins.php @@ -24,6 +24,8 @@ */ use tool_lifecycle\local\manager\lib_manager; +use tool_lifecycle\local\manager\step_manager; +use tool_lifecycle\local\manager\trigger_manager; use tool_lifecycle\tabs; use tool_lifecycle\urls; @@ -50,17 +52,16 @@ echo html_writer::link('https://github.com/learnweb/moodle-tool_lifecycle/wiki/List-of-Installed-Subplugins', get_string('documentationlink', 'tool_lifecycle'), ['target' => '_blank']); -$triggers = core_component::get_plugin_list('lifecycletrigger'); +$triggers = trigger_manager::get_trigger_types(); if ($triggers) { echo html_writer::div(get_string('triggers_installed', 'tool_lifecycle'), 'h2 mt-2'); foreach ($triggers as $trigger => $path) { $lib = lib_manager::get_trigger_lib($trigger); $triggericon = $lib->get_icon(); echo $OUTPUT->pix_icon($triggericon, $trigger, 'moodle', ['class' => 'mr-1']); - echo html_writer::div(get_string('pluginname', 'lifecycletrigger_' . $trigger), - "font-weight-bold d-inline-block"); + echo html_writer::div($lib->get_plugin_name(), "font-weight-bold d-inline-block"); try { - $plugindescription = get_string('plugindescription', 'lifecycletrigger_' . $trigger); + $plugindescription = $lib->get_plugin_description(); } catch (Exception $e) { $plugindescription = ""; } @@ -80,17 +81,16 @@ echo html_writer::div(get_string('adminsettings_notriggers', 'tool_lifecycle')); } -$steps = core_component::get_plugin_list('lifecyclestep'); +$steps = step_manager::get_step_types(); if ($steps) { echo html_writer::div(get_string('steps_installed', 'tool_lifecycle'), 'h2 mt-2'); foreach ($steps as $step => $path) { $lib = lib_manager::get_step_lib($step); $stepicon = $lib->get_icon(); echo $OUTPUT->pix_icon($stepicon, $step, 'moodle', ['class' => 'mr-1']); - echo html_writer::div(get_string('pluginname', 'lifecyclestep_' . $step), - "font-weight-bold d-inline-block"); + echo html_writer::div($lib->get_plugin_name(), "font-weight-bold d-inline-block"); try { - $plugindescription = get_string('plugindescription', 'lifecyclestep_' . $step); + $plugindescription = $lib->get_plugin_description(); } catch (Exception $e) { $plugindescription = ""; } diff --git a/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/interaction.php b/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/interaction.php new file mode 100644 index 00000000..87ee6d87 --- /dev/null +++ b/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/interaction.php @@ -0,0 +1,71 @@ +. + +namespace tool_samplestep\lifecycle; + +use tool_lifecycle\step\interactionlibbase; + +/** + * Sample interaction class for lifecycle step plugin. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class interaction extends interactionlibbase { + + /** + * Mock method to get the relevant capability for the interaction. + */ + public function get_relevant_capability() { + } + + /** + * Mock method to get the action tools for the interaction. + * + * @param \tool_lifecycle\local\entity\process $process + */ + public function get_action_tools($process) { + } + + /** + * Mock method to get the status message for the interaction. + * + * @param \tool_lifecycle\local\entity\process $process + * @return string status message + */ + public function get_status_message($process) { + } + + /** + * Mock method to get the action string for the interaction. + * + * @param string $action The action being performed. + * @param string $user html-link with username as text that refers to the user profile. + */ + public function get_action_string($action, $user) { + } + + /** + * Mock method to handle the interaction. + * + * @param \tool_lifecycle\local\entity\process $process + * @param \tool_lifecycle\local\entity\step_subplugin $step The lifecycle step object. + * @param string $action The action being performed. + */ + public function handle_interaction($process, $step, $action = 'default') { + } +} diff --git a/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/step.php b/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/step.php new file mode 100644 index 00000000..151cf127 --- /dev/null +++ b/tests/fixtures/fakeplugins/samplestep/classes/lifecycle/step.php @@ -0,0 +1,69 @@ +. + +namespace tool_samplestep\lifecycle; + +use tool_lifecycle\step\libbase; + + +/** + * Sample step class for lifecycle step plugin. + * + * @package tool_lifecycle + * @copyright 2026 Scott Verbeek + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class step extends libbase { + /** + * Returns the subplugin name. + * + * @return string + */ + public function get_subpluginname() { + return 'tool_samplestep'; + } + + /** + * Returns the plugin name. + * + * @return string + */ + public function get_plugin_name() { + return "Sample step"; + } + + /** + * Returns the plugin description. + * + * @return string + */ + public function get_plugin_description() { + return "Sample step plugin"; + } + + /** + * Processes the course for this step. + * + * @param int $processid The process ID. + * @param int $instanceid The instance ID. + * @param object $course The course object. + * @return null No action for this sample step. + */ + public function process_course($processid, $instanceid, $course) { + return null; + } + +} diff --git a/tests/fixtures/fakeplugins/samplestep/classes/privacy/provider.php b/tests/fixtures/fakeplugins/samplestep/classes/privacy/provider.php new file mode 100644 index 00000000..b285fbec --- /dev/null +++ b/tests/fixtures/fakeplugins/samplestep/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +namespace tool_samplestep\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for tool_samplestep. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason(): string { + return 'privacy:metadata'; + } +} diff --git a/tests/fixtures/fakeplugins/samplestep/lang/en/tool_samplestep.php b/tests/fixtures/fakeplugins/samplestep/lang/en/tool_samplestep.php new file mode 100644 index 00000000..f101c3fd --- /dev/null +++ b/tests/fixtures/fakeplugins/samplestep/lang/en/tool_samplestep.php @@ -0,0 +1,26 @@ +. + +/** + * Sample step language strings. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['pluginname'] = 'Sample step'; +$string['privacy:metadata'] = 'The plugin does not store any personal data.'; diff --git a/tests/fixtures/fakeplugins/samplestep/version.php b/tests/fixtures/fakeplugins/samplestep/version.php new file mode 100644 index 00000000..6530c77d --- /dev/null +++ b/tests/fixtures/fakeplugins/samplestep/version.php @@ -0,0 +1,29 @@ +. + +/** + * Fake component for testing + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2023100400; +$plugin->requires = 2022041200; +$plugin->component = 'tool_samplestep'; diff --git a/tests/fixtures/fakeplugins/sampletrigger/classes/lifecycle/trigger.php b/tests/fixtures/fakeplugins/sampletrigger/classes/lifecycle/trigger.php new file mode 100644 index 00000000..d955d80d --- /dev/null +++ b/tests/fixtures/fakeplugins/sampletrigger/classes/lifecycle/trigger.php @@ -0,0 +1,68 @@ +. + +namespace tool_sampletrigger\lifecycle; + +use tool_lifecycle\trigger\base_automatic; + +/** + * Sample trigger class for lifecycle trigger plugin. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class trigger extends base_automatic { + + /** + * Returns the subplugin name. + * + * @return string + */ + public function get_subpluginname() { + return 'tool_sampletrigger'; + } + + /** + * Returns the plugin name. + * + * @return string + */ + public function get_plugin_name() { + return "Sample trigger"; + } + + /** + * Returns the plugin description. + * + * @return string + */ + public function get_plugin_description() { + return "Sample trigger"; + } + + /** + * Checks the course for this trigger. + * + * @param object $course The course object. + * @param int $triggerid The trigger ID. + * @return null No action for this sample trigger. + */ + public function check_course($course, $triggerid) { + return null; + } + +} diff --git a/tests/fixtures/fakeplugins/sampletrigger/classes/privacy/provider.php b/tests/fixtures/fakeplugins/sampletrigger/classes/privacy/provider.php new file mode 100644 index 00000000..90260040 --- /dev/null +++ b/tests/fixtures/fakeplugins/sampletrigger/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +namespace tool_sampletrigger\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for tool_sampletrigger. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason(): string { + return 'privacy:metadata'; + } +} diff --git a/tests/fixtures/fakeplugins/sampletrigger/lang/en/tool_sampletrigger.php b/tests/fixtures/fakeplugins/sampletrigger/lang/en/tool_sampletrigger.php new file mode 100644 index 00000000..ac7956c2 --- /dev/null +++ b/tests/fixtures/fakeplugins/sampletrigger/lang/en/tool_sampletrigger.php @@ -0,0 +1,26 @@ +. + +/** + * Sample trigger language strings. + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['pluginname'] = 'Sample trigger'; +$string['privacy:metadata'] = 'The plugin does not store any personal data.'; diff --git a/tests/fixtures/fakeplugins/sampletrigger/version.php b/tests/fixtures/fakeplugins/sampletrigger/version.php new file mode 100644 index 00000000..bfe8816c --- /dev/null +++ b/tests/fixtures/fakeplugins/sampletrigger/version.php @@ -0,0 +1,29 @@ +. + +/** + * Fake component for testing + * + * @package tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2023100400; +$plugin->requires = 2022041200; +$plugin->component = 'tool_sampletrigger'; diff --git a/tests/subplugin_test.php b/tests/subplugin_test.php new file mode 100644 index 00000000..b60bf88c --- /dev/null +++ b/tests/subplugin_test.php @@ -0,0 +1,145 @@ +. + +namespace tool_lifecycle; + +use tool_lifecycle\local\manager\lib_manager; +use tool_lifecycle\local\manager\step_manager; +use tool_lifecycle\local\manager\trigger_manager; + +/** + * Tests the subplugin handling. + * @package tool_lifecycle + * @category test + * @group tool_lifecycle + * @copyright 2026 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +final class subplugin_test extends \advanced_testcase { + + /** + * Tests that all builtin triggers are registered and loadable. + * + * @covers \tool_lifecycle\local\manager\trigger_manager::get_trigger_types + * @covers \tool_lifecycle\local\manager\lib_manager::get_trigger_lib + */ + public function test_builtin_triggers(): void { + $this->resetAfterTest(); + $builtintriggers = \core_component::get_plugin_list('lifecycletrigger'); + $triggers = trigger_manager::get_trigger_types(); + + // All builtin triggers are also in the list of triggers. + $this->assertEmpty(array_diff_key($builtintriggers, $triggers)); + + // Trigger classes are loadable. + foreach ($builtintriggers as $triggername => $triggerpath) { + $this->assertNotEmpty(lib_manager::get_trigger_lib($triggername)); + } + } + + /** + * Tests that all builtin steps are registered and loadable. + * + * @covers \tool_lifecycle\local\manager\step_manager::get_step_types + * @covers \tool_lifecycle\local\manager\lib_manager::get_step_lib + */ + public function test_builtin_steps(): void { + $this->resetAfterTest(); + $builtinsteps = \core_component::get_plugin_list('lifecyclestep'); + $steps = step_manager::get_step_types(); + + // All builtin steps are also in the list of steps. + $this->assertEmpty(array_diff_key($builtinsteps, $steps)); + + // Step classes are loadable. + foreach ($builtinsteps as $stepname => $steppath) { + $this->assertNotEmpty(lib_manager::get_step_lib($stepname)); + } + } + + /** + * Tests that additional external triggers can be registered and loaded. + * + * @covers \tool_lifecycle\local\manager\trigger_manager::get_trigger_types + * @covers \tool_lifecycle\local\manager\lib_manager::get_trigger_lib + */ + public function test_additional_triggers(): void { + $this->resetAfterTest(); + + // Add a fake tool plugin, which define a trigger. + $mockedcomponent = new \ReflectionClass(\core_component::class); + $mockedplugins = $mockedcomponent->getProperty('plugins'); + $mockedplugins->setAccessible(true); + $plugins = $mockedplugins->getValue(); + $plugins['tool'] += ['sampletrigger' => __DIR__ . '/fixtures/fakeplugins/sampletrigger']; + $mockedplugins->setValue(null, $plugins); + + // The 'fixture' is not autoloaded, so we need to require it. + require_once(__DIR__ . '/fixtures/fakeplugins/sampletrigger/classes//lifecycle/trigger.php'); + + // Check if the trigger is available. + $triggers = trigger_manager::get_trigger_types(); + $this->assertArrayHasKey('tool_sampletrigger', $triggers); + + // Lib is loadable. + $this->assertInstanceOf('tool_sampletrigger\lifecycle\trigger', + lib_manager::get_trigger_lib('tool_sampletrigger')); + + // Unset the fake plugin. + unset($plugins['tool']['sampletrigger']); + $mockedplugins->setValue(null, $plugins); + } + + /** + * Tests that additional external steps and their interaction libs can be registered and loaded. + * + * @covers \tool_lifecycle\local\manager\step_manager::get_step_types + * @covers \tool_lifecycle\local\manager\lib_manager::get_step_lib + * @covers \tool_lifecycle\local\manager\lib_manager::get_step_interactionlib + */ + public function test_additional_steps(): void { + $this->resetAfterTest(); + + // Add a fake tool plugin, which define a step. + $mockedcomponent = new \ReflectionClass(\core_component::class); + $mockedplugins = $mockedcomponent->getProperty('plugins'); + $mockedplugins->setAccessible(true); + $plugins = $mockedplugins->getValue(); + $plugins['tool'] += ['samplestep' => __DIR__ . '/fixtures/fakeplugins/samplestep']; + $mockedplugins->setValue(null, $plugins); + + // The 'fixture' is not autoloaded, so we need to require it. + require_once(__DIR__ . '/fixtures/fakeplugins/samplestep/classes//lifecycle/step.php'); + require_once(__DIR__ . '/fixtures/fakeplugins/samplestep/classes//lifecycle/interaction.php'); + + // Check if the step is available. + $steps = step_manager::get_step_types(); + $this->assertArrayHasKey('tool_samplestep', $steps); + + // Lib is loadable. + $this->assertInstanceOf('tool_samplestep\lifecycle\step', + lib_manager::get_step_lib('tool_samplestep')); + + // Lib subtype is loadable. + $this->assertInstanceOf('tool_samplestep\lifecycle\interaction', + lib_manager::get_step_interactionlib('tool_samplestep')); + + // Unset the fake plugin. + unset($plugins['tool']['samplestep']); + $mockedplugins->setValue(null, $plugins); + } + +} diff --git a/trigger/lib.php b/trigger/lib.php index 6f12a222..3f595366 100644 --- a/trigger/lib.php +++ b/trigger/lib.php @@ -131,6 +131,40 @@ public function ensure_validity(array $settings): array { public function get_icon() { return 'i/nosubcat'; } + + /** + * Defgine name of the trigger. + * Allow subplugins to have custom names. + * + * @return string name of the trigger. + */ + public function get_plugin_name() { + return get_string("pluginname", "lifecycletrigger_" . $this->get_subpluginname()); + } + + /** + * Define description of the trigger. + * Allow subplugins to have custom description. + * + * @return string description of the trigger. + */ + public function get_plugin_description() { + return get_string("pluginname", "lifecycletrigger_" . $this->get_subpluginname()); + } + + /** + * Returns the settings of the trigger. + * + * @return void + */ + public function get_plugin_settings() { + $trigger = $this->get_subpluginname(); + $file = __DIR__ . "/$trigger/settings.php"; + + if (file_exists($file)) { + include($file); + } + } } /** diff --git a/version.php b/version.php index b4ab3380..62583d9f 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ $plugin->component = 'tool_lifecycle'; $plugin->maturity = MATURITY_STABLE; -$plugin->version = 2026012003; +$plugin->version = 2026012004; $plugin->requires = 2024100700; // Requires Moodle 4.5+. $plugin->supported = [405, 501]; $plugin->release = 'v5.1-r4';