// If we haven't preloaded information, load all the included inforef records to temp_ids table
$this->add_step(new restore_load_included_inforef_records('load_inforef_records'));
+ // If we haven't preloaded information, load all the needed roles to temp_ids_table
+ $this->add_step(new restore_load_and_map_roles('load_and_map_roles'));
+
// If we haven't preloaded information and are restoring user info, load all the needed users to temp_ids table
$this->add_step(new restore_load_included_users('load_user_records'));
// load it if needed:
// - it it is one of the annotated inforef files (course/section/activity/block)
- // - it is one "user", "group" or "grade" component file
+ // - it is one "user", "group", "grouping" or "grade" component file (that aren't sent to inforef ever)
$isfileref = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'fileref', $data->id);
- $iscomponent = ($data->component == 'user' || $data->component == 'group' || $data->component == 'grade');
+ $iscomponent = ($data->component == 'user' || $data->component == 'group' ||
+ $data->component == 'grouping' || $data->component == 'grade');
if ($isfileref || $iscomponent) {
restore_dbops::set_backup_files_record($this->get_restoreid(), $data);
}
}
}
+/**
+ * Execution step that, *conditionally* (if there isn't preloaded information),
+ * will load all the needed roles to backup_temp_ids. They will be stored with
+ * "role" itemname. Also it will perform one automatic mapping to roles existing
+ * in the target site, based in permissions of the user performing the restore,
+ * archetypes and other bits. At the end, each original role will have its associated
+ * target role or 0 if it's going to be skipped. Note we wrap everything over one
+ * restore_dbops method, as far as the same stuff is going to be also executed
+ * by restore prechecks
+ */
+class restore_load_and_map_roles extends restore_execution_step {
+
+ protected function define_execution() {
+ if ($this->task->get_preloaded_information()) { // if info is already preloaded, nothing to do
+ return;
+ }
+
+ $file = $this->get_basepath() . '/roles.xml';
+ // Load needed toles to temp_ids
+ restore_dbops::load_roles_to_tempids($this->get_restoreid(), $file);
+ // Process roles, mapping/skipping. Any error throws exception
+ restore_dbops::process_included_roles($this->get_restoreid(), $this->task->get_courseid(), $this->task->get_userid(), $this->task->is_samesite());
+ }
+}
+
/**
* Execution step that, *conditionally* (if there isn't preloaded information
* and users have been selected in settings, will load all the needed users
}
public function process_grouping($data) {
- debugging('TODO: Grouping restore not implemented. Detected grouping', DEBUG_DEVELOPER);
+ global $DB;
+
+ $data = (object)$data; // handy
+ $data->courseid = $this->get_courseid();
+
+ $oldid = $data->id; // need this saved for later
+ $restorefiles = false; // Only if we end creating the grouping
+
+ // Search if the grouping already exists (by name & description) in the target course
+ $description_clause = '';
+ $params = array('courseid' => $this->get_courseid(), 'grname' => $data->name);
+ if (!empty($data->description)) {
+ $description_clause = ' AND ' .
+ $DB->sql_compare_text('description') . ' = ' . $DB->sql_compare_text(':desc');
+ $params['desc'] = $data->description;
+ }
+ if (!$groupingdb = $DB->get_record_sql("SELECT *
+ FROM {groupings}
+ WHERE courseid = :courseid
+ AND name = :grname $description_clause", $params)) {
+ // grouping doesn't exist, create
+ $newitemid = $DB->insert_record('groupings', $data);
+ $restorefiles = true; // We'll restore the files
+ } else {
+ // grouping exists, use it
+ $newitemid = $groupingdb->id;
+ }
+ // Save the id mapping
+ $this->set_mapping('grouping', $oldid, $newitemid, $restorefiles);
}
public function process_grouping_group($data) {
- debugging('TODO: Grouping restore not implemented. Detected grouping group', DEBUG_DEVELOPER);
+ global $DB;
+
+ $data = (object)$data;
+
+ $data->groupingid = $this->get_new_parentid('grouping'); // Use new parentid
+ $data->groupid = $this->get_mappingid('group', $data->groupid); // Get from mappings
+ $DB->insert_record('groupings_groups', $data); // No need to set this mapping (no child info nor files)
}
protected function after_execute() {
// Add group related files, matching with "group" mappings
$this->add_related_files('group', 'icon', 'group');
$this->add_related_files('group', 'description', 'group');
+ // Add grouping related files, matching with "grouping" mappings
+ $this->add_related_files('grouping', 'description', 'grouping');
}
}
// Processing functions go here
public function process_course($data) {
+ // TODO: don't forget to remap defaultgroupingid
print_object('stopped before processing course. Continue here');
}
$xmlparser->process();
}
+ /**
+ * Load the needed role.xml file to backup_ids table for future reference
+ */
+ public static function load_roles_to_tempids($restoreid, $rolesfile) {
+
+ if (!file_exists($rolesfile)) { // Shouldn't happen ever, but...
+ throw new backup_helper_exception('missing_roles_xml_file', $rolesfile);
+ }
+ // Let's parse, custom processor will do its work, sending info to DB
+ $xmlparser = new progressive_parser();
+ $xmlparser->set_file($rolesfile);
+ $xmlprocessor = new restore_roles_parser_processor($restoreid);
+ $xmlparser->set_processor($xmlprocessor);
+ $xmlparser->process();
+ }
+
+ /**
+ * Precheck the loaded roles, return empty array if everything is ok, and
+ * array with 'errors', 'warnings' elements (suitable to be used by restore_prechecks)
+ * with any problem found
+ */
+ public static function precheck_included_roles($restoreid, $courseid, $userid, $samesite) {
+ debugging('implement the roles mapping/skip here. returns errors/warnings array', DEBUG_DEVELOPER);
+ return array();
+ }
+
+ /**
+ * Process the loaded roles, looking for their best mapping or skipping
+ * Any error will cause exception. Note this is one wrapper over
+ * precheck_included_roles, that contains all the logic, but returns
+ * errors/warnings instead and is executed as part of the restore prechecks
+ */
+ public static function process_included_roles($restoreid, $courseid, $userid, $samesite) {
+ global $DB;
+
+ // Just let precheck_included_roles() to do all the hard work
+ $problems = self::precheck_included_roles($restoreid, $courseid, $userid, $samesite);
+
+ // With problems of type error, throw exception, shouldn't happen if prechecks executed
+ if (array_key_exists('errors', $problems)) {
+ throw new restore_dbops_exception('restore_problems_processing_roles', null, implode(', ', $problems['errors']));
+ }
+ }
+
/**
* Load the needed users.xml file to backup_ids table for future reference
*/
$params = array($restoreid, $oldcontextid, $component, $filearea, $itemname);
}
- $rs = $DB->get_recordset_sql($sql, $params);
$fs = get_file_storage(); // Get moodle file storage
$basepath = $basepath . '/files/';// Get backup file pool base
+ $rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $rec) {
$file = (object)unserialize(base64_decode($rec->info));
// ignore root dirs (they are created automatically)
$errors = array();
$warnings = array();
+ // Some handy vars to be used along the prechecks
+ $samesite = $controller->is_samesite();
+ $restoreusers = $controller->get_plan()->get_setting('users')->get_value();
+ $hasmnetusers = (int)$controller->get_info()->mnet_remoteusers;
+ $restoreid = $controller->get_restoreid();
+ $courseid = $controller->get_courseid();
+ $userid = $controller->get_userid();
+ $inforeffiles = restore_dbops::get_needed_inforef_files($restoreid); // Get all inforef files
+
// Create temp tables
restore_controller_dbops::create_restore_temp_tables($controller->get_restoreid());
}
// If restoring to different site and restoring users and backup has mnet users warn/error
- $samesite = $controller->is_samesite();
- $restoreusers = $controller->get_plan()->get_setting('users')->get_value();
- $hasmnetusers = (int)$controller->get_info()->mnet_remoteusers;
if (!$samesite && $restoreusers && $hasmnetusers) {
// User is admin (can create users at sysctx), warn
if (has_capability('moodle/user:create', get_context_instance(CONTEXT_SYSTEM), $controller->get_userid())) {
}
}
+ // Load all the inforef files, we are going to need them
+ foreach ($inforeffiles as $inforeffile) {
+ restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile); // Load each inforef file to temp_ids
+ }
+
// If restoring users, check we are able to create all them
if ($restoreusers) {
$file = $controller->get_plan()->get_basepath() . '/users.xml';
- $restoreid = $controller->get_restoreid();
- $courseid = $controller->get_courseid();
- $userid = $controller->get_userid();
- $inforeffiles = restore_dbops::get_needed_inforef_files($restoreid); // Get all inforef files
- foreach ($inforeffiles as $inforeffile) {
- restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile); // Load each inforef file to temp_ids
- }
restore_dbops::load_users_to_tempids($restoreid, $file); // Load needed users to temp_ids
if ($problems = restore_dbops::precheck_included_users($restoreid, $courseid, $userid, $samesite)) {
$errors = array_merge($errors, $problems);
}
// TODO: Perform role_mappings, warning about non-mappable ones being ignored (see 1.9)
- // (restore won't create roles in any case)
+ // Note: restore won't create roles at all. Only mapping/skip!
+ $file = $controller->get_plan()->get_basepath() . '/roles.xml';
+ restore_dbops::load_roles_to_tempids($restoreid, $file); // Load needed users to temp_ids
+ if ($problems = restore_dbops::precheck_included_roles($restoreid, $courseid, $userid, $samesite)) {
+ $errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
+ $warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
+ }
// Prepare results and return
$results = array();
require_once($CFG->dirroot . '/backup/util/helper/restore_moodlexml_parser_processor.class.php');
require_once($CFG->dirroot . '/backup/util/helper/restore_inforef_parser_processor.class.php');
require_once($CFG->dirroot . '/backup/util/helper/restore_users_parser_processor.class.php');
+require_once($CFG->dirroot . '/backup/util/helper/restore_roles_parser_processor.class.php');
require_once($CFG->dirroot . '/backup/util/helper/restore_structure_parser_processor.class.php');
require_once($CFG->dirroot . '/backup/util/xml/parser/progressive_parser.class.php');
require_once($CFG->dirroot . '/backup/util/output/output_controller.class.php');