MDL-21432 backup - file handling and other changes. Saving before changes tomorrow...
authorEloy Lafuente <stronk7@moodle.org>
Sun, 18 Jul 2010 01:35:18 +0000 (01:35 +0000)
committerEloy Lafuente <stronk7@moodle.org>
Sun, 18 Jul 2010 01:35:18 +0000 (01:35 +0000)
backup/util/dbops/restore_dbops.class.php
backup/util/helper/backup_file_manager.class.php
backup/util/helper/backup_general_helper.class.php
backup/util/includes/restore_includes.php
backup/util/plan/restore_structure_step.class.php
backup/util/plan/restore_task.class.php

index 382bc0f..e68f374 100644 (file)
@@ -100,7 +100,7 @@ abstract class restore_dbops {
     public static function load_users_to_tempids($restoreid, $usersfile) {
 
         if (!file_exists($usersfile)) { // Shouldn't happen ever, but...
-            throw new backup_helper_exception('missing_users_xml_file', $inforeffile);
+            throw new backup_helper_exception('missing_users_xml_file', $usersfile);
         }
         // Let's parse, custom processor will do its work, sending info to DB
         $xmlparser = new progressive_parser();
@@ -110,6 +110,88 @@ abstract class restore_dbops {
         $xmlparser->process();
     }
 
+    /**
+     * Given one component/filearea/context and
+     * optionally one source itemname to match itemids
+     * put the corresponding files in the pool
+     */
+    public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $itemname = null) {
+        global $DB;
+
+        // Get new context, must exist or this will fail
+        if (!$newcontextid = self::get_backup_ids_record($restoreid, 'context', $oldcontextid)->newitemid) {
+            throw new restore_dbops_exception('unknown_context_mapping', $oldcontextid);
+        }
+
+        // Important: remember how files have been loaded to backup_ids_temp
+        //   - itemname: contains "file*component*fileara"
+        //   - itemid: contains the original id of the file
+        //   - newitemid: contains the itemid of the file
+        //   - parentitemid: contains the context of the file
+        //   - info: contains the whole original object (times, names...)
+        //   (all them being original ids as loaded from xml)
+
+        // itemname = null, we are going to match only by context, no need to use itemid (all them are 0)
+        if ($itemname == null) {
+            $sql = 'SELECT id, itemname, itemid, 0 AS newitemid
+                      FROM {backup_ids_temp}
+                     WHERE backupid = ?
+                       AND itemname = ?
+                       AND parentitemid = ?';
+            $params = array($restoreid, 'file*' . $component . '*' . $filearea, $oldcontextid);
+
+        // itemname not null, going to join by context and itemid, we'll need itemid (non zero)
+        } else {
+            $sql = 'SELECT f.id, f.itemname, f.itemid, i.newitemid
+                      FROM {backup_ids_temp} f
+                      JOIN {backup_ids_temp} i ON i.backupid = f.backupid
+                                              AND i.parentitemid = f.parentitemid
+                                              AND i.itemid = f.newitemid
+                     WHERE f.backupid = ?
+                       AND f.itemname = ?
+                       AND f.parentitemid = ?
+                       AND i.itemname = ?';
+            $params = array($restoreid, 'file*' . $component . '*' . $filearea, $oldcontextid, $itemname);
+        }
+
+        $rs = $DB->get_recordset_sql($sql, $params);
+        $fs = get_file_storage();         // Get moodle file storage
+        $basepath = $basepath . '/files/';// Get backup file pool base
+        foreach ($rs as $rec) {
+            $file = (object)self::get_backup_ids_record($restoreid, $rec->itemname, $rec->itemid)->info;
+            // ignore root dirs (they are created automatically)
+            if ($file->filepath == '/' && $file->filename == '.') {
+                continue;
+            }
+            // dir found (and not root one), let's create if
+            if ($file->filename == '.') {
+                $fs->create_directory($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath);
+                continue;
+            }
+            // arrived here, file found
+            // Find file in backup pool
+            $backuppath = $basepath . backup_file_manager::get_content_file_location($file->contenthash);
+            if (!file_exists($backuppath)) {
+                throw new restore_dbops_exception('file_not_found_in_pool', $file);
+            }
+            if (!$fs->file_exists($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->filename)) {
+                $file_record = array(
+                    'contextid'   => $newcontextid,
+                    'component'   => $component,
+                    'filearea'    => $filearea,
+                    'itemid'      => $rec->newitemid,
+                    'filepath'    => $file->filepath,
+                    'filename'    => $file->filename,
+                    'timecreated' => $file->timecreated,
+                    'timemodified'=> $file->timemodified,
+                    'author'      => $file->author,
+                    'license'     => $file->license);
+                $fs->create_file_from_pathname($file_record, $backuppath);
+            }
+        }
+        $rs->close();
+    }
+
     /**
      * Given one restoreid, create in DB all the users present
      * in backup_ids having newitemid = 0, as far as
@@ -117,7 +199,7 @@ abstract class restore_dbops {
      * ready to be created. Also, annotate their newids
      * once created for later reference
      */
-    protected static function create_included_users($restoreid) {
+    public static function create_included_users($basepath, $restoreid, $userfiles) {
         global $CFG, $DB;
 
         $authcache = array(); // Cache to get some bits from authentication plugins
@@ -244,7 +326,7 @@ abstract class restore_dbops {
 
             // Process preferences
             if (isset($user->preferences)) { // if present in backup
-                foreach($user->preferences as $preference) {
+                foreach($user->preferences['preference'] as $preference) {
                     $preference = (object)$preference;
                     // Prepare the record and insert it
                     $preference->userid = $newuserid;
@@ -252,6 +334,13 @@ abstract class restore_dbops {
                 }
             }
 
+            // Create user files in pool (profile, icon, private) by context
+            restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'icon', $recuser->parentitemid);
+            restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'profile', $recuser->parentitemid);
+            if ($userfiles) { // private files only if enabled in settings
+                restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'private', $recuser->parentitemid);
+            }
+
         }
         $rs->close();
     }
@@ -558,9 +647,6 @@ abstract class restore_dbops {
         if (!empty($problems)) {
             throw new restore_dbops_exception('restore_problems_processing_users', null, implode(', ', $problems));
         }
-
-        // Now, create all the users that we haven't been able to map
-        self::create_included_users($restoreid);
     }
 
 
index f8ff036..5e3f21b 100644 (file)
@@ -114,23 +114,4 @@ class backup_file_manager {
             }
         }
     }
-
-    /**
-     * Copy one file from backup storage to moodle storage
-     */
-    public static function copy_file_backup2moodle($backupid, $filerecorid) {
-        global $DB;
-
-        // Normalise param
-        if (!is_object($filerecorid)) {
-            $filerecorid = $DB->get_record('files', array('id' => $filerecorid));
-        }
-
-        // Directory, nothing to do
-        if ($filerecorid->filename === '.') {
-            return;
-        }
-
-        // TODO: Finish this on restore
-    }
 }
index c07b495..969fde0 100644 (file)
@@ -139,6 +139,7 @@ abstract class backup_general_helper extends backup_helper {
         $info->original_wwwroot         = $infoarr['original_wwwroot'];
         $info->original_site_identifier_hash = $infoarr['original_site_identifier_hash'];
         $info->original_course_id       = $infoarr['original_course_id'];
+        $info->original_course_contextid= $infoarr['original_course_contextid'];
         $info->type   =  $infoarr['details']['detail'][0]['type'];
         $info->format =  $infoarr['details']['detail'][0]['format'];
         $info->mode   =  $infoarr['details']['detail'][0]['mode'];
index ac07c7d..8a8161e 100644 (file)
@@ -32,6 +32,7 @@ require_once($CFG->dirroot . '/backup/util/interfaces/checksumable.class.php');
 require_once($CFG->dirroot . '/backup/util/interfaces/loggable.class.php');
 require_once($CFG->dirroot . '/backup/util/interfaces/executable.class.php');
 require_once($CFG->dirroot . '/backup/util/structure/restore_path_element.class.php');
+require_once($CFG->dirroot . '/backup/util/helper/backup_file_manager.class.php');
 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');
index dc0bd9a..7e326b6 100644 (file)
@@ -31,6 +31,8 @@ abstract class restore_structure_step extends restore_step {
 
     protected $filename; // Name of the file to be parsed
     protected $pathelements; // Array of pathelements to process
+    protected $elementsoldid; // Array to store last oldid used on each element
+    protected $elementsnewid; // Array to store last newid used on each element
 
     /**
      * Constructor - instantiates one object of this class
@@ -41,6 +43,8 @@ abstract class restore_structure_step extends restore_step {
         }
         $this->filename = $filename;
         $this->pathelements = array();
+        $this->elementsoldid = array();
+        $this->elementsnewid = array();
         parent::__construct($name, $task);
     }
 
@@ -68,6 +72,12 @@ abstract class restore_structure_step extends restore_step {
         // Get restore_path elements array adapting and preparing it for processing
         $this->pathelements = $this->prepare_pathelements($this->define_structure());
 
+        // Populate $elementsoldid and $elementsoldid based on available pathelements
+        foreach ($this->pathelements as $pathelement) {
+            $this->elementsoldid[$pathelement->get_name()] = null;
+            $this->elementsnewid[$pathelement->get_name()] = null;
+        }
+
         // Create parser and processor
         $xmlparser = new progressive_parser();
         $xmlparser->set_file($fullpath);
@@ -81,9 +91,10 @@ abstract class restore_structure_step extends restore_step {
 
         // And process it, dispatch to target methods in step will start automatically
         $xmlparser->process();
-    }
 
-// Protected API starts here
+        // Have finished, call to the after_execute method
+        $this->after_execute();
+    }
 
     /**
      * Receive one chunk of information form the xml parser processor and
@@ -107,6 +118,19 @@ abstract class restore_structure_step extends restore_step {
         }
     }
 
+// Protected API starts here
+
+    /**
+     * This method will be executed after the whole structure step have been processed
+     *
+     * After execution method for code needed to be executed after the whole structure
+     * has been processed. Useful for cleaning tasks, files process and others. Simply
+     * overwrite in in your steps if needed
+     */
+    protected function after_execute() {
+        // do nothing by default
+    }
+
     /**
      * Prepare the pathelements for processing, looking for duplicates, applying
      * processing objects and other adjustments
@@ -167,6 +191,64 @@ abstract class restore_structure_step extends restore_step {
         return true;
     }
 
+    /**
+     * To send ids pairs to backup_ids_table and to store them into paths
+     *
+     * This method will send the given itemname and old/new ids to the
+     * backup_ids_temp table, and, at the same time, will save the new id
+     * into the corresponding restore_path_element for easier access
+     * by children. Also will inject the known old context id for the task
+     * in case it's going to be used for restoring files later
+     */
+    protected function set_mapping($itemname, $oldid, $newid, $restorefiles = false) {
+        $parentitemid = $restorefiles ? $this->task->get_old_contextid() : null;
+        // Let's call the low level one
+        restore_dbops::set_backup_ids_record($this->get_restoreid(), $itemname, $oldid, $newid, $parentitemid);
+        // Now, if the itemname matches any pathelement->name, store the latest $newid
+        if (array_key_exists($itemname, $this->elementsoldid)) { // If present in  $this->elementsoldid, is valid, put both ids
+            $this->elementsoldid[$itemname] = $oldid;
+            $this->elementsnewid[$itemname] = $newid;
+        }
+    }
+
+    /**
+     * Returns the latest (parent) old id mapped by one pathelement
+     */
+    protected function get_old_parentid($itemname) {
+        return array_key_exists($itemname, $this->elementsoldid) ? $this->elementsoldid[$itemname] : null;
+    }
+
+    /**
+     * Returns the latest (parent) new id mapped by one pathelement
+     */
+    protected function get_new_parentid($itemname) {
+        return array_key_exists($itemname, $this->elementsnewid) ? $this->elementsnewid[$itemname] : null;
+    }
+
+    /**
+     * Return the new id of a mapping for the given itemname
+     *
+     */
+    protected function get_mappingid($itemname, $oldid) {
+        $mapping = $this->get_mapping($itemname, $oldid);
+        return $mapping ? $mapping->newitemid : false;
+    }
+
+    /**
+     * Return the complete mapping from the given itemname, itemid
+     */
+    protected function get_mapping($itemname, $oldid) {
+        return restore_dbops::get_backup_ids_record($this->get_restoreid(), $itemname, $oldid);
+    }
+
+    /**
+     * Add all the existing file, given their component and filearea and one backup_ids itemname to match with
+     */
+    protected function add_related_files($componentname, $filearea, $mappingitemname) {
+        restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $componentname,
+                                          $filearea, $this->task->get_old_contextid(), $mappingitemname);
+    }
+
     /**
      * Function that will return the structure to be processed by this restore_step.
      * Must return one array of @restore_path_element elements
index 194b0d6..a63ea10 100644 (file)
@@ -66,6 +66,10 @@ abstract class restore_task extends base_task {
     public function get_preloaded_information() {
         return $this->plan->get_preloaded_information();
     }
+
+    public function get_old_contextid() {
+        return $this->plan->get_info()->original_course_contextid;
+    }
 }
 
 /*