Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-27988 backup grade: Calculated grade items calculation references…

… now corrected and idnumber restore improved
  • Loading branch information...
commit 7bbf41661b949cda6edce48a2f78ad7077e3f976 1 parent 7fde489
Sam Hemelryk samhemelryk authored

Showing 1 changed file with 87 additions and 10 deletions. Show diff stats Hide diff stats

  1. +87 10 backup/moodle2/restore_stepslib.php
97 backup/moodle2/restore_stepslib.php
@@ -273,7 +273,9 @@ protected function process_grade_setting($data) {
273 273 //$this->set_mapping('grade_setting', $oldid, $newitemid);
274 274 }
275 275
276   - //put all activity grade items in the correct grade category and mark all for recalculation
  276 + /**
  277 + * put all activity grade items in the correct grade category and mark all for recalculation
  278 + */
277 279 protected function after_execute() {
278 280 global $DB;
279 281
@@ -284,8 +286,15 @@ protected function after_execute() {
284 286 );
285 287 $rs = $DB->get_recordset('backup_ids_temp', $conditions);
286 288
  289 + // We need this for calculation magic later on.
  290 + $mappings = array();
  291 +
287 292 if (!empty($rs)) {
288 293 foreach($rs as $grade_item_backup) {
  294 +
  295 + // Store the oldid with the new id.
  296 + $mappings[$grade_item_backup->itemid] = $grade_item_backup->newitemid;
  297 +
289 298 $updateobj = new stdclass();
290 299 $updateobj->id = $grade_item_backup->newitemid;
291 300
@@ -301,6 +310,55 @@ protected function after_execute() {
301 310 }
302 311 $rs->close();
303 312
  313 + // We need to update the calculations for calculated grade items that may reference old
  314 + // grade item ids using ##gi\d+##.
  315 + list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED);
  316 + $sql = "SELECT gi.id, gi.calculation
  317 + FROM {grade_items} gi
  318 + WHERE gi.id {$sql} AND
  319 + calculation IS NOT NULL";
  320 + $rs = $DB->get_recordset_sql($sql, $params);
  321 + foreach ($rs as $gradeitem) {
  322 + // Collect all of the used grade item id references
  323 + if (preg_match_all('/##gi(\d+)##/', $gradeitem->calculation, $matches) < 1) {
  324 + // This calculation doesn't reference any other grade items... EASY!
  325 + continue;
  326 + }
  327 + // For this next bit we are going to do the replacement of id's in two steps:
  328 + // 1. We will replace all old id references with a special mapping reference.
  329 + // 2. We will replace all mapping references with id's
  330 + // Why do we do this?
  331 + // Because there potentially there will be an overlap of ids within the query and we
  332 + // we substitute the wrong id.. safest way around this is the two step system
  333 + $calculationmap = array();
  334 + $mapcount = 0;
  335 + foreach ($matches[1] as $match) {
  336 + // Check that the old id is known to us, if not it was broken to begin with and will
  337 + // continue to be broken.
  338 + if (!array_key_exists($match, $mappings)) {
  339 + continue;
  340 + }
  341 + // Our special mapping key
  342 + $mapping = '##MAPPING'.$mapcount.'##';
  343 + // The old id that exists within the calculation now
  344 + $oldid = '##gi'.$match.'##';
  345 + // The new id that we want to replace the old one with.
  346 + $newid = '##gi'.$mappings[$match].'##';
  347 + // Replace in the special mapping key
  348 + $gradeitem->calculation = str_replace($oldid, $mapping, $gradeitem->calculation);
  349 + // And record the mapping
  350 + $calculationmap[$mapping] = $newid;
  351 + $mapcount++;
  352 + }
  353 + // Iterate all special mappings for this calculation and replace in the new id's
  354 + foreach ($calculationmap as $mapping => $newid) {
  355 + $gradeitem->calculation = str_replace($mapping, $newid, $gradeitem->calculation);
  356 + }
  357 + // Update the calculation now that its being remapped
  358 + $DB->update_record('grade_items', $gradeitem);
  359 + }
  360 + $rs->close();
  361 +
304 362 //need to correct the grade category path and parent
305 363 $conditions = array(
306 364 'courseid' => $this->get_courseid()
@@ -1800,28 +1858,47 @@ protected function define_structure() {
1800 1858 }
1801 1859
1802 1860 protected function process_grade_item($data) {
  1861 + global $DB;
1803 1862
1804 1863 $data = (object)($data);
1805 1864 $oldid = $data->id; // We'll need these later
1806 1865 $oldparentid = $data->categoryid;
  1866 + $courseid = $this->get_courseid();
1807 1867
1808 1868 // make sure top course category exists, all grade items will be associated
1809 1869 // to it. Later, if restoring the whole gradebook, categories will be introduced
1810   - $coursecat = grade_category::fetch_course_category($this->get_courseid());
  1870 + $coursecat = grade_category::fetch_course_category($courseid);
1811 1871 $coursecatid = $coursecat->id; // Get the categoryid to be used
1812 1872
  1873 + $idnumber = null;
  1874 + if (!empty($data->idnumber)) {
  1875 + // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
  1876 + // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
  1877 + // so the best is to keep the ones already in the gradebook
  1878 + // Potential problem: duplicates if same items are restored more than once. :-(
  1879 + // This needs to be fixed in some way (outcomes & activities with multiple items)
  1880 + // $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
  1881 + // In any case, verify always for uniqueness
  1882 + $sql = "SELECT cm.id
  1883 + FROM {course_modules} cm
  1884 + WHERE cm.course = :courseid AND
  1885 + cm.idnumber = :idnumber AND
  1886 + cm.id <> :cmid";
  1887 + $params = array(
  1888 + 'courseid' => $courseid,
  1889 + 'idnumber' => $data->idnumber,
  1890 + 'cmid' => $this->task->get_moduleid()
  1891 + );
  1892 + if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) {
  1893 + $idnumber = $data->idnumber;
  1894 + }
  1895 + }
  1896 +
1813 1897 unset($data->id);
1814 1898 $data->categoryid = $coursecatid;
1815 1899 $data->courseid = $this->get_courseid();
1816 1900 $data->iteminstance = $this->task->get_activityid();
1817   - // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
1818   - // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
1819   - // so the best is to keep the ones already in the gradebook
1820   - // Potential problem: duplicates if same items are restored more than once. :-(
1821   - // This needs to be fixed in some way (outcomes & activities with multiple items)
1822   - // $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
1823   - // In any case, verify always for uniqueness
1824   - $data->idnumber = grade_verify_idnumber($data->idnumber, $this->get_courseid()) ? $data->idnumber : null;
  1901 + $data->idnumber = $idnumber;
1825 1902 $data->scaleid = $this->get_mappingid('scale', $data->scaleid);
1826 1903 $data->outcomeid = $this->get_mappingid('outcome', $data->outcomeid);
1827 1904 $data->timecreated = $this->apply_date_offset($data->timecreated);

0 comments on commit 7bbf416

Please sign in to comment.
Something went wrong with that request. Please try again.