diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index a2b99c4b9979d..e1c6db33da3b9 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -2136,9 +2136,11 @@ protected function define_structure() { $activities = new backup_nested_element('activities'); - $activity = new backup_nested_element('activity', null, array( - 'moduleid', 'sectionid', 'modulename', 'title', - 'directory')); + $activity = new backup_nested_element( + 'activity', + null, + ['moduleid', 'sectionid', 'modulename', 'title', 'directory', 'insubsection'] + ); $sections = new backup_nested_element('sections'); diff --git a/backup/moodle2/restore_activity_task.class.php b/backup/moodle2/restore_activity_task.class.php index 4948516cd1108..6038fa03d7b79 100644 --- a/backup/moodle2/restore_activity_task.class.php +++ b/backup/moodle2/restore_activity_task.class.php @@ -100,6 +100,15 @@ public function get_moduleid() { return $this->moduleid; } + /** + * Return if the activity is inside a subsection. + * + * @return bool + */ + public function is_in_subsection(): bool { + return !empty($this->info->insubsection); + } + /** * Returns the old course module id (cmid of activity which will be restored) * @@ -312,7 +321,11 @@ protected function add_activity_included_setting(string $settingprefix): activit // - sectionincluded setting (if exists). $settingname = $settingprefix . 'included'; - $activityincluded = new restore_activity_generic_setting($settingname, base_setting::IS_BOOLEAN, true); + if ($this->is_in_subsection()) { + $activityincluded = new restore_subactivity_generic_setting($settingname, base_setting::IS_BOOLEAN, true); + } else { + $activityincluded = new restore_activity_generic_setting($settingname, base_setting::IS_BOOLEAN, true); + } $activityincluded->get_ui()->set_icon(new image_icon('monologo', get_string('pluginname', $this->modulename), $this->modulename, ['class' => 'iconlarge icon-post ml-1'])); @@ -351,7 +364,11 @@ protected function add_activity_userinfo_setting( $defaultvalue = true; } - $activityuserinfo = new restore_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + if ($this->is_in_subsection()) { + $activityuserinfo = new restore_subactivity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + } else { + $activityuserinfo = new restore_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + } if (!$defaultvalue) { // This is a bit hacky, but if there is no user data to restore, then diff --git a/backup/moodle2/restore_section_task.class.php b/backup/moodle2/restore_section_task.class.php index 924c309c67621..a9eb5730d3c83 100644 --- a/backup/moodle2/restore_section_task.class.php +++ b/backup/moodle2/restore_section_task.class.php @@ -56,6 +56,30 @@ public function get_taskbasepath() { return $this->get_basepath() . '/sections/section_' . $this->info->sectionid; } + /** + * Get the course module that is delegating this section. + * + * @return int|null the course module id that is delegating this section + */ + public function get_delegated_cm(): ?int { + if (!isset($this->info->parentcmid) || empty($this->info->parentcmid)) { + return null; + } + return intval($this->info->parentcmid); + } + + /** + * Get the delegated activity modname if any. + * + * @return string|null the modname of the delegated activity + */ + public function get_modname(): ?string { + if (!isset($this->info->modname) || empty($this->info->modname)) { + return null; + } + return $this->info->modname; + } + public function set_sectionid($sectionid) { $this->sectionid = $sectionid; } @@ -169,20 +193,35 @@ protected function add_section_included_setting(string $settingprefix): section_ // Define sectionincluded (to decide if the whole task must be really executed). $settingname = $settingprefix . 'included'; - $sectionincluded = new restore_section_included_setting($settingname, base_setting::IS_BOOLEAN, true); - - if (is_number($this->info->title)) { - $label = get_string('includesection', 'backup', $this->info->title); - } elseif (empty($this->info->title)) { // Don't throw error if title is empty, gracefully continue restore. - $this->log( - 'Section title missing in backup for section id ' . $this->info->sectionid, - backup::LOG_WARNING, - $this->name - ); - $label = get_string('unnamedsection', 'backup'); + $delegatedcmid = $this->get_delegated_cm(); + if ($delegatedcmid) { + $sectionincluded = new restore_subsection_included_setting($settingname, base_setting::IS_BOOLEAN, true); + // Subsections depends on the parent activity included setting. + $settingname = $this->get_modname() . '_' . $delegatedcmid . '_included'; + if ($this->plan->setting_exists($settingname)) { + $cmincluded = $this->plan->get_setting($settingname); + $cmincluded->add_dependency( + $sectionincluded, + ); + } + $label = get_string('subsectioncontent', 'backup'); } else { - $label = $this->info->title; + $sectionincluded = new restore_section_included_setting($settingname, base_setting::IS_BOOLEAN, true); + + if (is_number($this->info->title)) { + $label = get_string('includesection', 'backup', $this->info->title); + } else if (empty($this->info->title)) { // Don't throw error if title is empty, gracefully continue restore. + $this->log( + 'Section title missing in backup for section id ' . $this->info->sectionid, + backup::LOG_WARNING, + $this->name + ); + $label = get_string('unnamedsection', 'backup'); + } else { + $label = $this->info->title; + } } + $sectionincluded->get_ui()->set_label($label); $this->add_setting($sectionincluded); @@ -209,7 +248,20 @@ protected function add_section_userinfo_setting( $defaultvalue = true; } - $sectionuserinfo = new restore_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + $delegatedcmid = $this->get_delegated_cm(); + if ($delegatedcmid) { + $sectionuserinfo = new restore_subsection_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + // Subsections depends on the parent activity included setting. + $settingname = $this->get_modname() . '_' . $delegatedcmid . '_userinfo'; + if ($this->plan->setting_exists($settingname)) { + $cmincluded = $this->plan->get_setting($settingname); + $cmincluded->add_dependency( + $sectionuserinfo, + ); + } + } else { + $sectionuserinfo = new restore_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue); + } if (!$defaultvalue) { // This is a bit hacky, but if there is no user data to restore, then diff --git a/backup/moodle2/restore_settingslib.php b/backup/moodle2/restore_settingslib.php index cce77a98dece4..f62a7e433c7af 100644 --- a/backup/moodle2/restore_settingslib.php +++ b/backup/moodle2/restore_settingslib.php @@ -222,6 +222,39 @@ class restore_section_included_setting extends restore_section_generic_setting { */ class restore_section_userinfo_setting extends restore_section_generic_setting {} +/** + * Subsection base class (delegated section). + */ +class restore_subsection_generic_setting extends restore_section_generic_setting { + /** + * Class constructor. + * + * @param string $name Name of the setting + * @param string $vtype Type of the setting, for example base_setting::IS_TEXT + * @param mixed $value Value of the setting + * @param bool $visibility Is the setting visible in the UI, for example base_setting::VISIBLE + * @param int $status Status of the setting with regards to the locking, for example base_setting::NOT_LOCKED + */ + public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) { + parent::__construct($name, $vtype, $value, $visibility, $status); + $this->level = self::SUBSECTION_LEVEL; + } +} + +/** + * Setting to define if one subsection is included or no. + * + * Activities _included settings depend of them if available. + */ +class restore_subsection_included_setting extends restore_subsection_generic_setting { +} + +/** + * Subsection backup setting to control if section will include + * user information or no, depends of @restore_users_setting. + */ +class restore_subsection_userinfo_setting extends restore_subsection_generic_setting { +} // Activity backup settings @@ -243,6 +276,41 @@ class restore_activity_included_setting extends restore_activity_generic_setting */ class restore_activity_userinfo_setting extends restore_activity_generic_setting {} +/** + * Generic subactivity setting to pass various settings between tasks and steps + */ +class restore_subactivity_generic_setting extends restore_activity_generic_setting { + /** + * Class constructor. + * + * @param string $name Name of the setting + * @param string $vtype Type of the setting, for example base_setting::IS_TEXT + * @param mixed $value Value of the setting + * @param bool $visibility Is the setting visible in the UI, for example base_setting::VISIBLE + * @param int $status Status of the setting with regards to the locking, for example base_setting::NOT_LOCKED + */ + public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) { + parent::__construct($name, $vtype, $value, $visibility, $status); + $this->level = self::SUBACTIVITY_LEVEL; + } +} + +/** + * Subactivity backup setting to control if activity will be included or no. + * + * Depends of restore_activities_setting and optionally parent section included setting. + */ +class restore_subactivity_included_setting extends restore_subactivity_generic_setting { +} + +/** + * Subactivity backup setting to control if activity will include user information. + * + * Depends of restore_users_setting. + */ +class restore_subactivity_userinfo_setting extends restore_subactivity_generic_setting { +} + /** * root setting to control if restore will create content bank content or no */ diff --git a/backup/util/dbops/backup_controller_dbops.class.php b/backup/util/dbops/backup_controller_dbops.class.php index 612daedf8ad1a..f022b76b70da7 100644 --- a/backup/util/dbops/backup_controller_dbops.class.php +++ b/backup/util/dbops/backup_controller_dbops.class.php @@ -234,7 +234,9 @@ private static function get_activity_backup_information($task) { 'sectionid' => $task->get_sectionid(), 'modulename' => $task->get_modulename(), 'title' => $task->get_name(), - 'directory' => 'activities/' . $task->get_modulename() . '_' . $task->get_moduleid()); + 'directory' => 'activities/' . $task->get_modulename() . '_' . $task->get_moduleid(), + 'insubsection' => ($task->is_in_subsection()) ? 1 : '', + ); // Now get activity settings // Calculate prefix to find valid settings