diff --git a/backup/moodle2/backup_format_softcourse_plugin.class.php b/backup/moodle2/backup_format_softcourse_plugin.class.php new file mode 100644 index 0000000..fab4026 --- /dev/null +++ b/backup/moodle2/backup_format_softcourse_plugin.class.php @@ -0,0 +1,52 @@ +. + +/** + * format_softcourse course format. + * Provides the information to backup grid course format + * + * @package format_softcourse + * @copyright 2026 Pimenko . + * @category backup + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class backup_format_softcourse_plugin extends backup_format_plugin { + /** + * Returns the format information to attach to section element + */ + protected function define_course_plugin_structure() { + + // Define the virtual plugin element with the condition to fulfill. + $plugin = $this->get_plugin_element( + null, + '/course/format', + 'softcourse', + ); + + // Create one standard named plugin element (the visible container). + $pluginwrapper = new backup_nested_element($this->get_recommended_name()); + + $plugin->add_child($pluginwrapper); + + // Introduction. + $pluginwrapper->annotate_files('format_softcourse', 'introduction', null); + + // Section image. + $pluginwrapper->annotate_files('format_softcourse', 'sectionimage', null); + + return $plugin; + } +} diff --git a/backup/moodle2/restore_format_softcourse_plugin.class.php b/backup/moodle2/restore_format_softcourse_plugin.class.php index 18ea62f..c61ddcf 100644 --- a/backup/moodle2/restore_format_softcourse_plugin.class.php +++ b/backup/moodle2/restore_format_softcourse_plugin.class.php @@ -15,16 +15,7 @@ // along with Moodle. If not, see . /** - * Specialised restore for format_softcourse - * - * @package format_softcourse - * @category backup - * @copyright 2021 Pimenko - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Specialised restore for format_softcourse + * Specialised restore for format_softcourse. * * Processes 'numsections' from the old backup files and hides sections that used to be "orphaned" * @@ -34,7 +25,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_format_softcourse_plugin extends restore_format_plugin { - /** @var int */ protected $originalnumsections = 0; @@ -61,11 +51,14 @@ public function define_course_plugin_structure() { // Since this method is executed before the restore we can do some pre-checks here. // In case of merging backup into existing course find the current number of sections. $target = $this->step->get_task()->get_target(); - if (($target == backup::TARGET_CURRENT_ADDING || $target == backup::TARGET_EXISTING_ADDING) && - $this->need_restore_numsections()) { + if ( + ($target == backup::TARGET_CURRENT_ADDING || $target == backup::TARGET_EXISTING_ADDING) && + $this->need_restore_numsections() + ) { $maxsection = $DB->get_field_sql( 'SELECT max(section) FROM {course_sections} WHERE course = ?', - [$this->step->get_task()->get_courseid()]); + [$this->step->get_task()->get_courseid()] + ); $this->originalnumsections = (int)$maxsection; } @@ -77,7 +70,6 @@ public function define_course_plugin_structure() { * Dummy process method */ public function process_dummy_course() { - } /** @@ -86,7 +78,31 @@ public function process_dummy_course() { * This method is only executed if course configuration was overridden */ public function after_restore_course() { - global $DB; + global $DB, $CFG; + + $this->add_related_files('format_softcourse', 'introduction', null); + $this->add_related_files('format_softcourse', 'sectionimage', 'course_section'); + + $courseid = $this->step->get_task()->get_courseid(); + $newcontext = \context_course::instance($courseid); + + $record = $DB->get_record('course_format_options', [ + 'courseid' => $courseid, + 'format' => 'softcourse', + 'name' => 'introduction', + ]); + + if ($record && !empty($record->value)) { + $newvalue = preg_replace( + '/\$@PLUGINFILEBYCONTEXT\*\d+@\$/', + $CFG->wwwroot . '/pluginfile.php/' . $newcontext->id, + $record->value + ); + if ($newvalue !== $record->value) { + $record->value = $newvalue; + $DB->update_record('course_format_options', $record); + } + } if (!$this->need_restore_numsections()) { // Backup file was made in Moodle 3.3 or later, we don't need to process 'numsecitons'. @@ -110,8 +126,10 @@ public function after_restore_course() { if ($this->step->get_task()->get_setting_value($key . '_included')) { $sectionnum = (int)$section->title; if ($sectionnum > $numsections && $sectionnum > $this->originalnumsections) { - $DB->execute("UPDATE {course_sections} SET visible = 0 WHERE course = ? AND section = ?", - [$this->step->get_task()->get_courseid(), $sectionnum]); + $DB->execute( + "UPDATE {course_sections} SET visible = 0 WHERE course = ? AND section = ?", + [$this->step->get_task()->get_courseid(), $sectionnum] + ); } } } diff --git a/classes/output/courseformat/content.php b/classes/output/courseformat/content.php index 568a359..10c1a06 100644 --- a/classes/output/courseformat/content.php +++ b/classes/output/courseformat/content.php @@ -34,12 +34,10 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class content extends content_base { - /** * @var bool Topic format has add section after each topic. * * The responsible for the buttons is core_courseformat\output\local\content\section. */ protected $hasaddsection = true; - } diff --git a/classes/output/courseformat/content/section.php b/classes/output/courseformat/content/section.php index af81b2a..c987a5f 100644 --- a/classes/output/courseformat/content/section.php +++ b/classes/output/courseformat/content/section.php @@ -38,7 +38,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class section extends section_base { - /** @var course_format the course format */ protected $format; @@ -75,7 +74,7 @@ public function export_for_template(\renderer_base $output): stdClass { // Single pass: initialize section fields once, attach cminfo, and compute completion in the same loop. $hidesectionzero = (int) ($format->get_format_options()['hidesectionzero'] ?? 0) === 1; - $sectionFieldsSet = false; + $sectionfieldsset = false; $nbcomplete = 0; $nbcompletion = 0; @@ -93,7 +92,7 @@ public function export_for_template(\renderer_base $output): stdClass { } // Initialize section-level data only once (avoid overwriting on subsequent iterations). - if (!$sectionFieldsSet) { + if (!$sectionfieldsset) { $info = $modinfo->get_section_info($idsection); $data->idsection = $idsection; $data->name = $info->name ?? null; @@ -102,7 +101,7 @@ public function export_for_template(\renderer_base $output): stdClass { $data->visible = (int) ($info->visible ?? 0); $data->available = (bool) ($info->available ?? false); $data->skip = false; - $sectionFieldsSet = true; + $sectionfieldsset = true; } // Attach cminfo so templates and later logic can access full CM data. @@ -148,8 +147,10 @@ public function export_for_template(\renderer_base $output): stdClass { } // If the section itself is hidden or not available, skip rendering it. - if ((isset($data->visible) && (int) $data->visible === 0) || (isset($data->uservisible) && $data->uservisible === false) || - (isset($data->available) && $data->available === false)) { + if ( + (isset($data->visible) && (int) $data->visible === 0) || (isset($data->uservisible) && $data->uservisible === false) || + (isset($data->available) && $data->available === false) + ) { $data->skip = true; return $data; } @@ -157,11 +158,11 @@ public function export_for_template(\renderer_base $output): stdClass { // If there is only one CM and it is hidden/unavailable on the course page, skip. if (isset($data->cmlist) && isset($data->cmlist->cms) && count($data->cmlist->cms) === 1) { $only = $data->cmlist->cms[0]->cminfo ?? null; - $onlyHiddenOrUnavailable = ($only && isset($only->visible) && (int) $only->visible === 0) || + $onlyhiddenorunavailable = ($only && isset($only->visible) && (int) $only->visible === 0) || ($only && isset($only->visibleoncoursepage) && (int) $only->visibleoncoursepage === 0) || ($only && isset($only->uservisible) && $only->uservisible === false) || ($only && isset($only->available) && $only->available === false); - if ($onlyHiddenOrUnavailable) { + if ($onlyhiddenorunavailable) { $data->skip = true; return $data; } @@ -199,10 +200,7 @@ public function export_for_template(\renderer_base $output): stdClass { ); // Capability checks for section image edit/delete actions. - if (has_capability( - 'moodle/course:update', - $context, - )) { + if (has_capability('moodle/course:update', $context)) { $data->update_img = get_string( 'update_img', 'format_softcourse', @@ -266,29 +264,29 @@ public function export_for_template(\renderer_base $output): stdClass { * * @param object $cm The course module object, which may include or reference cm_info. * @param stdClass $data The data object containing details about activities and URLs. - * @param \completion_info $completioninfo The completion information object + * @param \completion_info $completioninfo The completion information object. + * @param int $nbcompletion The total number of completion items. + * @param int $nbcomplete The number of completed items. + * @return void */ - function get_completion($cm, $data, $completioninfo, $nbcompletion, $nbcomplete) { - - // Determine if the desired information is in $cm or $cm->cminfo + public function get_completion($cm, $data, $completioninfo, $nbcompletion, $nbcomplete) { + // Determine if the desired information is in $cm or $cm->cminfo. $cminfo = null; if (is_object($cm)) { if ($cm instanceof \cm_info) { $cminfo = $cm; - } else if (property_exists( - $cm, - 'cminfo', - ) && $cm->cminfo instanceof \cm_info) { + } else if (property_exists($cm, 'cminfo') && $cm->cminfo instanceof \cm_info) { $cminfo = $cm->cminfo; } } if ($cminfo !== null) { - - if ($cminfo->get_user_visible() && + if ( + $cminfo->get_user_visible() && (isset($cminfo->available) && $cminfo->available) && (($cminfo->uservisible && !$cminfo->is_stealth() && $cminfo->modname != 'label') || !empty($cm->url)) && - $data->first_cm_url == '') { + $data->first_cm_url == '' + ) { if ($cminfo->modname == 'resource') { $cminfo->url->param( 'forceview', @@ -311,8 +309,10 @@ function get_completion($cm, $data, $completioninfo, $nbcompletion, $nbcomplete) true, )->completionstate; - if ($cminfo->deletioninprogress == 0 && $cminfo->visible == 1 && $cminfo->modname != "label" && - $cminfo->visibleoncoursepage == 1 && $cminfo->uservisible && $cminfo->available == true) { + if ( + $cminfo->deletioninprogress == 0 && $cminfo->visible == 1 && $cminfo->modname != "label" && + $cminfo->visibleoncoursepage == 1 && $cminfo->uservisible && $cminfo->available == true + ) { $data->countactivities += 1; } } @@ -320,7 +320,7 @@ function get_completion($cm, $data, $completioninfo, $nbcompletion, $nbcomplete) return [ $data, $nbcompletion, - $nbcomplete + $nbcomplete, ]; } } diff --git a/classes/output/renderer.php b/classes/output/renderer.php index 7cb3fb1..5f41cec 100644 --- a/classes/output/renderer.php +++ b/classes/output/renderer.php @@ -38,7 +38,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class renderer extends section_renderer { - /** * @var stdClass Course */ @@ -125,10 +124,9 @@ public function render_content($widget) { $options, ); - if ($this->page->user_is_editing() && has_capability( - 'moodle/course:update', - $context, - )) { + if ( + $this->page->user_is_editing() && has_capability('moodle/course:update', $context) + ) { // Base template. $content = $this->render_from_template( 'core_courseformat/local/content', @@ -151,7 +149,6 @@ public function render_content($widget) { } if ($this->courseformat->get_format_options()['hideallsections'] == 1) { - if (!$data->start_url) { foreach ($data->sections as $section) { if ($section->skip != true && $section->start_url != null) { @@ -161,7 +158,6 @@ public function render_content($widget) { } } $data->sections = false; - } else { if (!$data->start_url) { foreach ($data->sections as $section) { @@ -239,10 +235,12 @@ protected function section_edit_control_items($course, $section, $onsectionpage ); $controls = []; - if ($section->section && has_capability( + if ( + $section->section && has_capability( 'moodle/course:setcurrentsection', $coursecontext, - )) { + ) + ) { if ($course->marker == $section->section) { // Show the "light globe" on/off. $url->param( 'marker', @@ -295,10 +293,7 @@ protected function section_edit_control_items($course, $section, $onsectionpage ); // If the edit key exists, we are going to insert our controls after it. - if (array_key_exists( - "edit", - $parentcontrols, - )) { + if (array_key_exists("edit", $parentcontrols)) { $merged = []; // We can't use splice because we are using associative arrays. // Step through the array and merge the arrays. diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index b7c8f17..178cfe5 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -30,7 +30,6 @@ * @package YourPackageName */ class provider implements \core_privacy\local\metadata\null_provider { - /** * Get the language string identifier with the component's language * file to explain why this plugin stores no data. diff --git a/db/upgrade.php b/db/upgrade.php index 001692b..02fe090 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -34,7 +34,6 @@ function xmldb_format_softcourse_upgrade($oldversion) { require_once($CFG->dirroot . '/course/format/softcourse/db/upgradelib.php'); if ($oldversion < 2017020200) { - // Remove 'numsections' option and hide or delete orphaned sections. format_softcourse_upgrade_remove_numsections(); @@ -48,7 +47,6 @@ function xmldb_format_softcourse_upgrade($oldversion) { // Put any upgrade step following this. if ($oldversion < 2018030900) { - // During upgrade to Moodle 3.3 it could happen that general section (section 0) became 'invisible'. // It should always be visible. $DB->execute("UPDATE {course_sections} SET visible=1 WHERE visible=0 AND section=0 AND course IN @@ -57,7 +55,6 @@ function xmldb_format_softcourse_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2018030900, 'format', 'softcourse'); } if ($oldversion < 2019103100) { - // Get all sections 0 of courses having softcourse course format. $sectionsrequest = 'SELECT s.id, s.course, s.summary FROM {course_sections} s diff --git a/externallib.php b/externallib.php index 7fc671e..bafb516 100644 --- a/externallib.php +++ b/externallib.php @@ -37,7 +37,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class format_softcourse_external extends external_api { - /** * Updates the section image for a given course section. * diff --git a/format.php b/format.php index 7088a51..69eef06 100644 --- a/format.php +++ b/format.php @@ -25,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/filelib.php'); -require_once($CFG->libdir.'/completionlib.php'); +require_once($CFG->libdir . '/filelib.php'); +require_once($CFG->libdir . '/completionlib.php'); $context = context_course::instance($course->id); // Retrieve course format option fields and add them to the $course object. diff --git a/lib.php b/lib.php index 17c9515..0ab0a0a 100644 --- a/lib.php +++ b/lib.php @@ -36,7 +36,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class format_softcourse extends core_courseformat\base { - /** * Returns true if this course format uses sections. * @@ -123,10 +122,9 @@ public function get_view_url($section, $options = []) { [ 'id' => $course->id ], ); - if (array_key_exists( - 'sr', - $options, - ) && !is_null($options['sr'])) { + if ( + array_key_exists('sr', $options) && !is_null($options['sr']) + ) { $sectionno = $options['sr']; } else if (is_object($section)) { $sectionno = $section->section; @@ -136,10 +134,7 @@ public function get_view_url($section, $options = []) { if ($this->uses_sections() && $sectionno !== null) { // The url includes the parameter to expand the section by default. - if (!array_key_exists( - 'expanded', - $options, - )) { + if (!array_key_exists('expanded', $options)) { $options['expanded'] = true; } if ($options['expanded']) { @@ -244,10 +239,12 @@ public function extend_course_navigation($navigation, navigation_node $node) { null, PARAM_INT, ); - if ($selectedsection !== null && (!defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0') && $PAGE->url->compare( + if ( + $selectedsection !== null && (!defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0') && $PAGE->url->compare( new moodle_url('/course/view.php'), URL_MATCH_BASE, - )) { + ) + ) { $navigation->includesectionnum = $selectedsection; } } @@ -292,14 +289,8 @@ public function update_course_format_options($data, $oldcourse = null) { $oldcourse = (array) $oldcourse; $options = $this->course_format_options(); foreach ($options as $key => $unused) { - if (!array_key_exists( - $key, - $data, - )) { - if (array_key_exists( - $key, - $oldcourse, - )) { + if (!array_key_exists($key, $data)) { + if (array_key_exists($key, $oldcourse)) { $data[$key] = $oldcourse[$key]; } } @@ -586,8 +577,8 @@ protected function validate_format_options(array $rawdata, ?int $sectionid = nul $data[$name . 'format'] = clean_param($data[$key]['format'], PARAM_INT); } unset($data[$key]); - } elseif ($key == 'introduction') { - // TODO rework this : introduction should be named 'introduction_editor' and not 'introduction'. + } else if ($key == 'introduction') { + // TODO MDL-99999 rework this : introduction should be named 'introduction_editor' and not 'introduction'. // Also fix data structure of introduction element. if (is_string($data[$key])) { $data[$key] = clean_param($data[$key], $option['type'] ?? PARAM_RAW); diff --git a/version.php b/version.php index 4ddecc0..df4833d 100644 --- a/version.php +++ b/version.php @@ -24,8 +24,8 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2026042401; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2026070900; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2025100600; // Requires this Moodle version. $plugin->component = 'format_softcourse'; // Full name of the plugin (used for diagnostics). -$plugin->release = '4.7.1'; +$plugin->release = '4.7.2'; $plugin->maturity = MATURITY_STABLE;