Skip to content

Commit

Permalink
MDL-27988 backup grade: Calculated grade items calculation references…
Browse files Browse the repository at this point in the history
… now corrected and idnumber restore improved
  • Loading branch information
Sam Hemelryk authored and stronk7 committed Jun 29, 2011
1 parent 8277c39 commit 746f1ac
Showing 1 changed file with 87 additions and 10 deletions.
97 changes: 87 additions & 10 deletions backup/moodle2/restore_stepslib.php
Expand Up @@ -273,7 +273,9 @@ protected function process_grade_setting($data) {
//$this->set_mapping('grade_setting', $oldid, $newitemid); //$this->set_mapping('grade_setting', $oldid, $newitemid);
} }


//put all activity grade items in the correct grade category and mark all for recalculation /**
* put all activity grade items in the correct grade category and mark all for recalculation
*/
protected function after_execute() { protected function after_execute() {
global $DB; global $DB;


Expand All @@ -284,8 +286,15 @@ protected function after_execute() {
); );
$rs = $DB->get_recordset('backup_ids_temp', $conditions); $rs = $DB->get_recordset('backup_ids_temp', $conditions);


// We need this for calculation magic later on.
$mappings = array();

if (!empty($rs)) { if (!empty($rs)) {
foreach($rs as $grade_item_backup) { foreach($rs as $grade_item_backup) {

// Store the oldid with the new id.
$mappings[$grade_item_backup->itemid] = $grade_item_backup->newitemid;

$updateobj = new stdclass(); $updateobj = new stdclass();
$updateobj->id = $grade_item_backup->newitemid; $updateobj->id = $grade_item_backup->newitemid;


Expand All @@ -301,6 +310,55 @@ protected function after_execute() {
} }
$rs->close(); $rs->close();


// We need to update the calculations for calculated grade items that may reference old
// grade item ids using ##gi\d+##.
list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED);
$sql = "SELECT gi.id, gi.calculation
FROM {grade_items} gi
WHERE gi.id {$sql} AND
calculation IS NOT NULL";
$rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $gradeitem) {
// Collect all of the used grade item id references
if (preg_match_all('/##gi(\d+)##/', $gradeitem->calculation, $matches) < 1) {
// This calculation doesn't reference any other grade items... EASY!
continue;
}
// For this next bit we are going to do the replacement of id's in two steps:
// 1. We will replace all old id references with a special mapping reference.
// 2. We will replace all mapping references with id's
// Why do we do this?
// Because there potentially there will be an overlap of ids within the query and we
// we substitute the wrong id.. safest way around this is the two step system
$calculationmap = array();
$mapcount = 0;
foreach ($matches[1] as $match) {
// Check that the old id is known to us, if not it was broken to begin with and will
// continue to be broken.
if (!array_key_exists($match, $mappings)) {
continue;
}
// Our special mapping key
$mapping = '##MAPPING'.$mapcount.'##';
// The old id that exists within the calculation now
$oldid = '##gi'.$match.'##';
// The new id that we want to replace the old one with.
$newid = '##gi'.$mappings[$match].'##';
// Replace in the special mapping key
$gradeitem->calculation = str_replace($oldid, $mapping, $gradeitem->calculation);
// And record the mapping
$calculationmap[$mapping] = $newid;
$mapcount++;
}
// Iterate all special mappings for this calculation and replace in the new id's
foreach ($calculationmap as $mapping => $newid) {
$gradeitem->calculation = str_replace($mapping, $newid, $gradeitem->calculation);
}
// Update the calculation now that its being remapped
$DB->update_record('grade_items', $gradeitem);
}
$rs->close();

//need to correct the grade category path and parent //need to correct the grade category path and parent
$conditions = array( $conditions = array(
'courseid' => $this->get_courseid() 'courseid' => $this->get_courseid()
Expand Down Expand Up @@ -1800,28 +1858,47 @@ protected function define_structure() {
} }


protected function process_grade_item($data) { protected function process_grade_item($data) {
global $DB;


$data = (object)($data); $data = (object)($data);
$oldid = $data->id; // We'll need these later $oldid = $data->id; // We'll need these later
$oldparentid = $data->categoryid; $oldparentid = $data->categoryid;
$courseid = $this->get_courseid();


// make sure top course category exists, all grade items will be associated // make sure top course category exists, all grade items will be associated
// to it. Later, if restoring the whole gradebook, categories will be introduced // to it. Later, if restoring the whole gradebook, categories will be introduced
$coursecat = grade_category::fetch_course_category($this->get_courseid()); $coursecat = grade_category::fetch_course_category($courseid);
$coursecatid = $coursecat->id; // Get the categoryid to be used $coursecatid = $coursecat->id; // Get the categoryid to be used


$idnumber = null;
if (!empty($data->idnumber)) {
// Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
// Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
// so the best is to keep the ones already in the gradebook
// Potential problem: duplicates if same items are restored more than once. :-(
// This needs to be fixed in some way (outcomes & activities with multiple items)
// $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
// In any case, verify always for uniqueness
$sql = "SELECT cm.id
FROM {course_modules} cm
WHERE cm.course = :courseid AND
cm.idnumber = :idnumber AND
cm.id <> :cmid";
$params = array(
'courseid' => $courseid,
'idnumber' => $data->idnumber,
'cmid' => $this->task->get_moduleid()
);
if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) {
$idnumber = $data->idnumber;
}
}

unset($data->id); unset($data->id);
$data->categoryid = $coursecatid; $data->categoryid = $coursecatid;
$data->courseid = $this->get_courseid(); $data->courseid = $this->get_courseid();
$data->iteminstance = $this->task->get_activityid(); $data->iteminstance = $this->task->get_activityid();
// Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber $data->idnumber = $idnumber;
// Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
// so the best is to keep the ones already in the gradebook
// Potential problem: duplicates if same items are restored more than once. :-(
// This needs to be fixed in some way (outcomes & activities with multiple items)
// $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
// In any case, verify always for uniqueness
$data->idnumber = grade_verify_idnumber($data->idnumber, $this->get_courseid()) ? $data->idnumber : null;
$data->scaleid = $this->get_mappingid('scale', $data->scaleid); $data->scaleid = $this->get_mappingid('scale', $data->scaleid);
$data->outcomeid = $this->get_mappingid('outcome', $data->outcomeid); $data->outcomeid = $this->get_mappingid('outcome', $data->outcomeid);
$data->timecreated = $this->apply_date_offset($data->timecreated); $data->timecreated = $this->apply_date_offset($data->timecreated);
Expand Down

0 comments on commit 746f1ac

Please sign in to comment.