MDL-21432 - backup finished groupings restore + introduced role precheck/execution...
authorEloy Lafuente <stronk7@moodle.org>
Mon, 19 Jul 2010 14:06:16 +0000 (14:06 +0000)
committerEloy Lafuente <stronk7@moodle.org>
Mon, 19 Jul 2010 14:06:16 +0000 (14:06 +0000)
backup/moodle2/restore_root_task.class.php
backup/moodle2/restore_stepslib.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/restore_prechecks_helper.class.php
backup/util/includes/restore_includes.php

index 004809a..c2d0f7d 100644 (file)
@@ -40,6 +40,9 @@ class restore_root_task extends restore_task {
         // 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'));
 
index 98dc45b..04d761b 100644 (file)
@@ -108,15 +108,41 @@ class restore_load_included_files extends restore_structure_step {
 
         // 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
@@ -243,17 +269,53 @@ class restore_groups_structure_step extends restore_structure_step {
     }
 
     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');
     }
 
 }
@@ -339,6 +401,7 @@ class restore_course_structure_step extends restore_structure_step {
 
     // Processing functions go here
     public function process_course($data) {
+        // TODO: don't forget to remap defaultgroupingid
         print_object('stopped before processing course. Continue here');
     }
 
index 3a68ce2..80f478b 100644 (file)
@@ -94,6 +94,50 @@ abstract class restore_dbops {
         $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
      */
@@ -152,9 +196,9 @@ abstract class restore_dbops {
             $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)
index 87d5c7e..bf90cc1 100644 (file)
@@ -49,6 +49,15 @@ abstract class restore_prechecks_helper {
         $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());
 
@@ -78,9 +87,6 @@ abstract class restore_prechecks_helper {
         }
 
         // 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())) {
@@ -91,16 +97,14 @@ abstract class restore_prechecks_helper {
             }
         }
 
+        // 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);
@@ -108,7 +112,13 @@ abstract class restore_prechecks_helper {
         }
 
         // 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();
index ad9dca7..d211bf9 100644 (file)
@@ -38,6 +38,7 @@ require_once($CFG->dirroot . '/backup/util/helper/restore_prechecks_helper.class
 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');