Línea 488... |
Línea 488... |
488 |
|
488 |
|
489 |
// Ensure the module cache is current when recalculating grades.
|
489 |
// Ensure the module cache is current when recalculating grades.
|
Línea 490... |
Línea 490... |
490 |
rebuild_course_cache($this->get_courseid(), true);
|
490 |
rebuild_course_cache($this->get_courseid(), true);
|
491 |
|
491 |
|
492 |
// Restore marks items as needing update. Update everything now.
|
492 |
// Restore marks items as needing update. Update everything now.
|
Línea 493... |
Línea 493... |
493 |
grade_regrade_final_grades($this->get_courseid());
|
493 |
grade_regrade_final_grades($this->get_courseid(), async: true);
|
494 |
}
|
494 |
}
|
495 |
|
495 |
|
Línea 1157... |
Línea 1157... |
1157 |
|
1157 |
|
1158 |
// Do not include group/groupings information if not requested.
|
1158 |
// Do not include group/groupings information if not requested.
|
1159 |
$groupinfo = $this->get_setting_value('groups');
|
1159 |
$groupinfo = $this->get_setting_value('groups');
|
1160 |
if ($groupinfo) {
|
1160 |
if ($groupinfo) {
|
1161 |
$paths[] = new restore_path_element('group', '/groups/group');
|
- |
|
1162 |
$paths[] = new restore_path_element('groupcustomfield', '/groups/groupcustomfields/groupcustomfield');
|
1161 |
$paths[] = new restore_path_element('group', '/groups/group');
|
1163 |
$paths[] = new restore_path_element('grouping', '/groups/groupings/grouping');
|
- |
|
1164 |
$paths[] = new restore_path_element('groupingcustomfield',
|
- |
|
1165 |
'/groups/groupings/groupingcustomfields/groupingcustomfield');
|
1162 |
$paths[] = new restore_path_element('grouping', '/groups/groupings/grouping');
|
- |
|
1163 |
$paths[] = new restore_path_element('grouping_group', '/groups/groupings/grouping/grouping_groups/grouping_group');
|
- |
|
1164 |
|
- |
|
1165 |
// Custom fields.
|
- |
|
1166 |
if ($this->get_setting_value('customfield')) {
|
- |
|
1167 |
$paths[] = new restore_path_element('groupcustomfield', '/groups/groupcustomfields/groupcustomfield');
|
- |
|
1168 |
$paths[] = new restore_path_element('groupingcustomfield',
|
- |
|
1169 |
'/groups/groupings/groupingcustomfields/groupingcustomfield');
|
1166 |
$paths[] = new restore_path_element('grouping_group', '/groups/groupings/grouping/grouping_groups/grouping_group');
|
1170 |
}
|
1167 |
}
|
1171 |
}
|
1168 |
return $paths;
|
1172 |
return $paths;
|
Línea 1169... |
Línea 1173... |
1169 |
}
|
1173 |
}
|
Línea 1233... |
Línea 1237... |
1233 |
* @param array $data data for group custom field
|
1237 |
* @param array $data data for group custom field
|
1234 |
* @return void
|
1238 |
* @return void
|
1235 |
*/
|
1239 |
*/
|
1236 |
public function process_groupcustomfield($data) {
|
1240 |
public function process_groupcustomfield($data) {
|
1237 |
$newgroup = $this->get_mapping('group', $data['groupid']);
|
1241 |
$newgroup = $this->get_mapping('group', $data['groupid']);
|
- |
|
1242 |
if ($newgroup && $newgroup->newitemid) {
|
1238 |
$data['groupid'] = $newgroup->newitemid ?? $data['groupid'];
|
1243 |
$data['groupid'] = $newgroup->newitemid;
|
1239 |
$handler = \core_group\customfield\group_handler::create();
|
1244 |
$handler = \core_group\customfield\group_handler::create();
|
1240 |
$handler->restore_instance_data_from_backup($this->task, $data);
|
1245 |
$handler->restore_instance_data_from_backup($this->task, $data);
|
- |
|
1246 |
}
|
1241 |
}
|
1247 |
}
|
Línea 1242... |
Línea 1248... |
1242 |
|
1248 |
|
1243 |
public function process_grouping($data) {
|
1249 |
public function process_grouping($data) {
|
Línea 1289... |
Línea 1295... |
1289 |
* Restore grouping custom field values.
|
1295 |
* Restore grouping custom field values.
|
1290 |
* @param array $data data for grouping custom field
|
1296 |
* @param array $data data for grouping custom field
|
1291 |
* @return void
|
1297 |
* @return void
|
1292 |
*/
|
1298 |
*/
|
1293 |
public function process_groupingcustomfield($data) {
|
1299 |
public function process_groupingcustomfield($data) {
|
1294 |
$newgroup = $this->get_mapping('grouping', $data['groupingid']);
|
1300 |
$newgrouping = $this->get_mapping('grouping', $data['groupingid']);
|
- |
|
1301 |
if ($newgrouping && $newgrouping->newitemid) {
|
1295 |
$data['groupingid'] = $newgroup->newitemid ?? $data['groupingid'];
|
1302 |
$data['groupingid'] = $newgrouping->newitemid;
|
1296 |
$handler = \core_group\customfield\grouping_handler::create();
|
1303 |
$handler = \core_group\customfield\grouping_handler::create();
|
1297 |
$handler->restore_instance_data_from_backup($this->task, $data);
|
1304 |
$handler->restore_instance_data_from_backup($this->task, $data);
|
- |
|
1305 |
}
|
1298 |
}
|
1306 |
}
|
Línea 1299... |
Línea 1307... |
1299 |
|
1307 |
|
1300 |
public function process_grouping_group($data) {
|
1308 |
public function process_grouping_group($data) {
|
Línea 1610... |
Línea 1618... |
1610 |
// Look for the section
|
1618 |
// Look for the section
|
1611 |
$section = new stdclass();
|
1619 |
$section = new stdclass();
|
1612 |
$section->course = $this->get_courseid();
|
1620 |
$section->course = $this->get_courseid();
|
1613 |
$section->section = $data->number;
|
1621 |
$section->section = $data->number;
|
1614 |
$section->timemodified = $data->timemodified ?? 0;
|
1622 |
$section->timemodified = $data->timemodified ?? 0;
|
- |
|
1623 |
$section->component = null;
|
- |
|
1624 |
$section->itemid = null;
|
- |
|
1625 |
|
- |
|
1626 |
$secrec = $DB->get_record(
|
- |
|
1627 |
'course_sections',
|
- |
|
1628 |
['course' => $this->get_courseid(), 'section' => $data->number, 'component' => null]
|
- |
|
1629 |
);
|
- |
|
1630 |
$createsection = empty($secrec);
|
- |
|
1631 |
|
- |
|
1632 |
// Delegated sections are always restored as new sections.
|
- |
|
1633 |
if (!empty($data->component)) {
|
- |
|
1634 |
$section->itemid = $this->get_delegated_section_mapping($data->component, $data->itemid);
|
- |
|
1635 |
// If the delegate component does not set the mapping id, the section must be converted
|
- |
|
1636 |
// into a regular section. Otherwise, it won't be accessible.
|
- |
|
1637 |
$createsection = $createsection || $section->itemid !== null;
|
- |
|
1638 |
$section->component = ($section->itemid !== null) ? $data->component : null;
|
- |
|
1639 |
// The section number will be always the last of the course, no matter the case.
|
- |
|
1640 |
$section->section = $this->get_last_section_number($this->get_courseid()) + 1;
|
- |
|
1641 |
|
- |
|
1642 |
}
|
1615 |
// Section doesn't exist, create it with all the info from backup
|
1643 |
// Section doesn't exist, create it with all the info from backup
|
1616 |
if (!$secrec = $DB->get_record('course_sections', ['course' => $this->get_courseid(), 'section' => $data->number])) {
|
1644 |
if ($createsection) {
|
1617 |
$section->name = $data->name;
|
1645 |
$section->name = $data->name;
|
1618 |
$section->summary = $data->summary;
|
1646 |
$section->summary = $data->summary;
|
1619 |
$section->summaryformat = $data->summaryformat;
|
1647 |
$section->summaryformat = $data->summaryformat;
|
1620 |
$section->sequence = '';
|
1648 |
$section->sequence = '';
|
1621 |
$section->visible = $data->visible;
|
1649 |
$section->visible = $data->visible;
|
Línea 1627... |
Línea 1655... |
1627 |
if (is_null($section->availability)) {
|
1655 |
if (is_null($section->availability)) {
|
1628 |
$section->availability = \core_availability\info::convert_legacy_fields(
|
1656 |
$section->availability = \core_availability\info::convert_legacy_fields(
|
1629 |
$data, true);
|
1657 |
$data, true);
|
1630 |
}
|
1658 |
}
|
1631 |
}
|
1659 |
}
|
1632 |
// Moodle 4.4 implement basic delegated section logic but it is not able to restore
|
- |
|
- |
|
1660 |
|
1633 |
// them from a backup. To prevent unexpected retoration errors, all sections with
|
1661 |
// Delegated sections should be always after the normal sections.
|
1634 |
// a component will be restored as a normal section.
|
1662 |
$this->displace_delegated_sections_after($section->section);
|
1635 |
$section->component = null;
|
- |
|
1636 |
$section->itemid = null;
|
- |
|
- |
|
1663 |
|
1637 |
$newitemid = $DB->insert_record('course_sections', $section);
|
1664 |
$newitemid = $DB->insert_record('course_sections', $section);
|
1638 |
$section->id = $newitemid;
|
1665 |
$section->id = $newitemid;
|
Línea 1639... |
Línea 1666... |
1639 |
|
1666 |
|
Línea 1803... |
Línea 1830... |
1803 |
|
1830 |
|
1804 |
protected function after_execute() {
|
1831 |
protected function after_execute() {
|
1805 |
// Add section related files, with 'course_section' itemid to match
|
1832 |
// Add section related files, with 'course_section' itemid to match
|
1806 |
$this->add_related_files('course', 'section', 'course_section');
|
1833 |
$this->add_related_files('course', 'section', 'course_section');
|
- |
|
1834 |
}
|
- |
|
1835 |
|
- |
|
1836 |
/**
|
- |
|
1837 |
* Create a delegate section mapping.
|
- |
|
1838 |
*
|
- |
|
1839 |
* @param string $component the component name (frankenstyle)
|
- |
|
1840 |
* @param int $oldsectionid The old section id.
|
- |
|
1841 |
* @return int|null The new section id or null if not found.
|
- |
|
1842 |
*/
|
- |
|
1843 |
protected function get_delegated_section_mapping($component, $oldsectionid): ?int {
|
- |
|
1844 |
$result = $this->get_mappingid("course_section::$component", $oldsectionid, null);
|
- |
|
1845 |
return $result;
|
- |
|
1846 |
}
|
- |
|
1847 |
|
- |
|
1848 |
/**
|
- |
|
1849 |
* Displace delegated sections after the given section number.
|
- |
|
1850 |
*
|
- |
|
1851 |
* @param int $sectionnum The section number.
|
- |
|
1852 |
*/
|
- |
|
1853 |
protected function displace_delegated_sections_after(int $sectionnum): void {
|
- |
|
1854 |
global $DB;
|
- |
|
1855 |
|
- |
|
1856 |
$sectionstomove = $DB->get_records_select(
|
- |
|
1857 |
'course_sections',
|
- |
|
1858 |
'course = ? AND component IS NOT NULL',
|
- |
|
1859 |
[$this->get_courseid()],
|
- |
|
1860 |
'section DESC', 'id, section'
|
- |
|
1861 |
);
|
- |
|
1862 |
// Here we add the new section to the end of the list so we make sure that all delegated sections are really
|
- |
|
1863 |
// all located after the normal sections. We can have case where delegated sections are located before the
|
- |
|
1864 |
// normal sections, so we need to move them to the end (mostly in the restore process more than in the duplicate
|
- |
|
1865 |
// process in which the order sections => delegated section is mostly there).
|
- |
|
1866 |
$sectionnum = $sectionnum + count($sectionstomove);
|
- |
|
1867 |
foreach ($sectionstomove as $section) {
|
- |
|
1868 |
$section->section = $sectionnum--;
|
- |
|
1869 |
$DB->update_record('course_sections', $section);
|
- |
|
1870 |
}
|
- |
|
1871 |
}
|
- |
|
1872 |
|
- |
|
1873 |
/**
|
- |
|
1874 |
* Get the last section number in the course.
|
- |
|
1875 |
*
|
- |
|
1876 |
* @param int $courseid The course id.
|
- |
|
1877 |
* @param bool $includedelegated If true, include delegated sections in the count.
|
- |
|
1878 |
* @return int The last section number.
|
- |
|
1879 |
*/
|
- |
|
1880 |
protected function get_last_section_number(int $courseid, bool $includedelegated = false): int {
|
- |
|
1881 |
global $DB;
|
- |
|
1882 |
|
- |
|
1883 |
$delegtadefilter = $includedelegated ? '' : ' AND component IS NULL';
|
- |
|
1884 |
|
- |
|
1885 |
return (int) $DB->get_field_sql(
|
- |
|
1886 |
'SELECT max(section) from {course_sections} WHERE course = ?' . $delegtadefilter,
|
- |
|
1887 |
[$courseid]
|
- |
|
1888 |
);
|
1807 |
}
|
1889 |
}
|
Línea 1808... |
Línea 1890... |
1808 |
}
|
1890 |
}
|
1809 |
|
1891 |
|
1810 |
/**
|
1892 |
/**
|
Línea 1830... |
Línea 1912... |
1830 |
*/
|
1912 |
*/
|
1831 |
protected $legacyallowedmodules = array();
|
1913 |
protected $legacyallowedmodules = array();
|
Línea 1832... |
Línea 1914... |
1832 |
|
1914 |
|
Línea -... |
Línea 1915... |
- |
|
1915 |
protected function define_structure() {
|
- |
|
1916 |
|
1833 |
protected function define_structure() {
|
1917 |
$paths = [];
|
- |
|
1918 |
|
1834 |
|
1919 |
$course = new restore_path_element('course', '/course');
|
1835 |
$course = new restore_path_element('course', '/course');
|
1920 |
$paths[] = $course;
|
1836 |
$category = new restore_path_element('category', '/course/category');
|
1921 |
$paths[] = new restore_path_element('category', '/course/category');
|
1837 |
$tag = new restore_path_element('tag', '/course/tags/tag');
|
1922 |
$paths[] = new restore_path_element('tag', '/course/tags/tag');
|
- |
|
1923 |
$paths[] = new restore_path_element('course_format_option', '/course/courseformatoptions/courseformatoption');
|
- |
|
1924 |
$paths[] = new restore_path_element('allowed_module', '/course/allowed_modules/module');
|
- |
|
1925 |
|
1838 |
$customfield = new restore_path_element('customfield', '/course/customfields/customfield');
|
1926 |
// Custom fields.
|
- |
|
1927 |
if ($this->get_setting_value('customfield')) {
|
Línea 1839... |
Línea 1928... |
1839 |
$courseformatoptions = new restore_path_element('course_format_option', '/course/courseformatoptions/courseformatoption');
|
1928 |
$paths[] = new restore_path_element('customfield', '/course/customfields/customfield');
|
1840 |
$allowedmodule = new restore_path_element('allowed_module', '/course/allowed_modules/module');
|
1929 |
}
|
Línea 1841... |
Línea 1930... |
1841 |
|
1930 |
|
Línea 1858... |
Línea 1947... |
1858 |
$this->add_plugin_structure('local', $course);
|
1947 |
$this->add_plugin_structure('local', $course);
|
Línea 1859... |
Línea 1948... |
1859 |
|
1948 |
|
1860 |
// Apply for admin tool plugins optional paths at course level.
|
1949 |
// Apply for admin tool plugins optional paths at course level.
|
Línea 1861... |
Línea 1950... |
1861 |
$this->add_plugin_structure('tool', $course);
|
1950 |
$this->add_plugin_structure('tool', $course);
|
1862 |
|
1951 |
|
Línea 1863... |
Línea 1952... |
1863 |
return array($course, $category, $tag, $customfield, $allowedmodule, $courseformatoptions);
|
1952 |
return $paths;
|
1864 |
}
|
1953 |
}
|
1865 |
|
1954 |
|
Línea 2702... |
Línea 2791... |
2702 |
'notification' => $data->notification,
|
2791 |
'notification' => $data->notification,
|
2703 |
'status' => BADGE_STATUS_INACTIVE,
|
2792 |
'status' => BADGE_STATUS_INACTIVE,
|
2704 |
'nextcron' => $data->nextcron,
|
2793 |
'nextcron' => $data->nextcron,
|
2705 |
'version' => $data->version,
|
2794 |
'version' => $data->version,
|
2706 |
'language' => $data->language,
|
2795 |
'language' => $data->language,
|
2707 |
'imageauthorname' => $data->imageauthorname,
|
- |
|
2708 |
'imageauthoremail' => $data->imageauthoremail,
|
- |
|
2709 |
'imageauthorurl' => $data->imageauthorurl,
|
- |
|
2710 |
'imagecaption' => $data->imagecaption
|
2796 |
'imagecaption' => $data->imagecaption
|
2711 |
);
|
2797 |
);
|
Línea 2712... |
Línea 2798... |
2712 |
|
2798 |
|
2713 |
$newid = $DB->insert_record('badge', $params);
|
2799 |
$newid = $DB->insert_record('badge', $params);
|
Línea 4906... |
Línea 4992... |
4906 |
// Do the mapping for modulename, preparing it for files by oldcontext
|
4992 |
// Do the mapping for modulename, preparing it for files by oldcontext
|
4907 |
$modulename = $this->task->get_modulename();
|
4993 |
$modulename = $this->task->get_modulename();
|
4908 |
$oldid = $this->task->get_old_activityid();
|
4994 |
$oldid = $this->task->get_old_activityid();
|
4909 |
$this->set_mapping($modulename, $oldid, $newitemid, true);
|
4995 |
$this->set_mapping($modulename, $oldid, $newitemid, true);
|
4910 |
}
|
4996 |
}
|
- |
|
4997 |
|
- |
|
4998 |
/**
|
- |
|
4999 |
* Create a delegate section mapping.
|
- |
|
5000 |
*
|
- |
|
5001 |
* @param string $component The component name (frankenstyle)
|
- |
|
5002 |
* @param int $olditemid The old section id.
|
- |
|
5003 |
* @param int $newitemid The new section id.
|
- |
|
5004 |
*/
|
- |
|
5005 |
protected function set_delegated_section_mapping($component, $olditemid, $newitemid) {
|
- |
|
5006 |
$this->set_mapping("course_section::$component", $olditemid, $newitemid);
|
- |
|
5007 |
}
|
4911 |
}
|
5008 |
}
|
Línea 4912... |
Línea 5009... |
4912 |
|
5009 |
|
4913 |
/**
|
5010 |
/**
|
4914 |
* Structure step in charge of creating/mapping all the qcats and qs
|
5011 |
* Structure step in charge of creating/mapping all the qcats and qs
|
Línea 4919... |
Línea 5016... |
4919 |
class restore_create_categories_and_questions extends restore_structure_step {
|
5016 |
class restore_create_categories_and_questions extends restore_structure_step {
|
Línea 4920... |
Línea 5017... |
4920 |
|
5017 |
|
4921 |
/** @var array $cachedcategory store a question category */
|
5018 |
/** @var array $cachedcategory store a question category */
|
Línea -... |
Línea 5019... |
- |
|
5019 |
protected $cachedcategory = null;
|
- |
|
5020 |
|
- |
|
5021 |
/** @var stdClass the last question_bank_entry seen during the restore. Processed when we get to a question. */
|
- |
|
5022 |
protected $latestqbe;
|
- |
|
5023 |
|
- |
|
5024 |
/** @var stdClass the last question_version seen during the restore. Processed when we get to a question. */
|
4922 |
protected $cachedcategory = null;
|
5025 |
protected $latestversion;
|
Línea 4923... |
Línea 5026... |
4923 |
|
5026 |
|
4924 |
protected function define_structure() {
|
5027 |
protected function define_structure() {
|
4925 |
|
5028 |
|
Línea 5003... |
Línea 5106... |
5003 |
if ($mapping->info->contextlevel == CONTEXT_MODULE) {
|
5106 |
if ($mapping->info->contextlevel == CONTEXT_MODULE) {
|
5004 |
$mapping->parentitemid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
5107 |
$mapping->parentitemid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
5005 |
}
|
5108 |
}
|
5006 |
$data->contextid = $mapping->parentitemid;
|
5109 |
$data->contextid = $mapping->parentitemid;
|
Línea -... |
Línea 5110... |
- |
|
5110 |
|
- |
|
5111 |
$context = \context::instance_by_id($data->contextid);
|
5007 |
|
5112 |
|
5008 |
// Before 3.5, question categories could be created at top level.
|
5113 |
// Before 3.5, question categories could be created at top level.
|
5009 |
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
5114 |
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
5010 |
$restoretask = $this->get_task();
|
5115 |
$restoretask = $this->get_task();
|
- |
|
5116 |
$before35 = $restoretask->backup_release_compare('3.5', '<') || $restoretask->backup_version_compare(20180205, '<');
|
- |
|
5117 |
|
- |
|
5118 |
// We need a 'Top' question category for an activity module and activity modules are mapped to CONTEXT_COURSE and moved
|
- |
|
5119 |
// to the correct module context in restore_move_module_questions_categories.
|
- |
|
5120 |
// As we can't create a 'Top' category in CONTEXT_COURSE we'll make a default
|
5011 |
$before35 = $restoretask->backup_release_compare('3.5', '<') || $restoretask->backup_version_compare(20180205, '<');
|
5121 |
// qbank module and map it to that until they are created later.
|
- |
|
5122 |
if (empty($mapping->info->parent) && $before35) {
|
- |
|
5123 |
if ($context->contextlevel === CONTEXT_COURSE) {
|
- |
|
5124 |
$course = get_course($context->instanceid);
|
- |
|
5125 |
$defaultbank = \core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
|
- |
|
5126 |
$bankcontextid = $defaultbank->context->id;
|
- |
|
5127 |
} else {
|
- |
|
5128 |
$bankcontextid = $data->contextid;
|
5012 |
if (empty($mapping->info->parent) && $before35) {
|
5129 |
}
|
5013 |
$top = question_get_top_category($data->contextid, true);
|
5130 |
$top = question_get_top_category($bankcontextid, true);
|
5014 |
$data->parent = $top->id;
|
5131 |
$data->parent = $top->id;
|
Línea 5015... |
Línea 5132... |
5015 |
}
|
5132 |
}
|
5016 |
|
- |
|
5017 |
if (empty($data->parent)) {
|
- |
|
5018 |
if (!$top = question_get_top_category($data->contextid)) {
|
- |
|
5019 |
$top = question_get_top_category($data->contextid, true);
|
- |
|
5020 |
$this->set_mapping('question_category_created', $oldid, $top->id, false, null, $data->contextid);
|
- |
|
5021 |
}
|
- |
|
5022 |
$this->set_mapping('question_category', $oldid, $top->id);
|
- |
|
5023 |
} else {
|
5133 |
|
5024 |
|
5134 |
if (!empty($data->parent)) {
|
5025 |
// Before 3.1, the 'stamp' field could be erroneously duplicated.
|
5135 |
// Before 3.1, the 'stamp' field could be erroneously duplicated.
|
5026 |
// From 3.1 onwards, there's a unique index of (contextid, stamp).
|
5136 |
// From 3.1 onwards, there's a unique index of (contextid, stamp).
|
5027 |
// If we encounter a duplicate in an old restore file, just generate a new stamp.
|
5137 |
// If we encounter a duplicate in an old restore file, just generate a new stamp.
|
Línea 5044... |
Línea 5154... |
5044 |
$this->set_mapping('question_category_created', $oldid, $newitemid, false, null, $data->contextid);
|
5154 |
$this->set_mapping('question_category_created', $oldid, $newitemid, false, null, $data->contextid);
|
5045 |
}
|
5155 |
}
|
5046 |
}
|
5156 |
}
|
Línea 5047... |
Línea 5157... |
5047 |
|
5157 |
|
5048 |
/**
|
5158 |
/**
|
5049 |
* Process pre 4.0 question data where in creates the record for version and entry table.
|
5159 |
* Set up date to allow restore of questions from pre-4.0 backups.
|
5050 |
*
|
5160 |
*
|
5051 |
* @param array $data the data from the XML file.
|
5161 |
* @param stdClass $data the data from the XML file.
|
5052 |
*/
|
5162 |
*/
|
- |
|
5163 |
protected function process_question_legacy_data($data) {
|
- |
|
5164 |
$this->latestqbe = (object) [
|
- |
|
5165 |
'id' => $data->id,
|
- |
|
5166 |
'questioncategoryid' => $data->category,
|
- |
|
5167 |
'ownerid' => $data->createdby,
|
5053 |
protected function process_question_legacy_data($data) {
|
5168 |
'idnumber' => $data->idnumber ?? null,
|
Línea 5054... |
Línea -... |
5054 |
global $DB;
|
- |
|
5055 |
|
5169 |
];
|
5056 |
$oldid = $data->id;
|
5170 |
|
5057 |
// Process question bank entry.
|
- |
|
5058 |
$entrydata = new stdClass();
|
- |
|
5059 |
$entrydata->questioncategoryid = $data->category;
|
5171 |
$this->latestversion = (object) [
|
5060 |
$userid = $this->get_mappingid('user', $data->createdby);
|
- |
|
5061 |
if ($userid) {
|
- |
|
5062 |
$entrydata->ownerid = $userid;
|
- |
|
5063 |
} else {
|
- |
|
5064 |
if (!$this->task->is_samesite()) {
|
- |
|
5065 |
$entrydata->ownerid = $this->task->get_userid();
|
- |
|
5066 |
}
|
- |
|
5067 |
}
|
- |
|
5068 |
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
- |
|
5069 |
if (isset($data->idnumber) && !$DB->record_exists('question_bank_entries',
|
5172 |
'id' => $data->id,
|
5070 |
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->category])) {
|
- |
|
5071 |
$entrydata->idnumber = $data->idnumber;
|
- |
|
5072 |
}
|
- |
|
5073 |
|
- |
|
5074 |
$newentryid = $DB->insert_record('question_bank_entries', $entrydata);
|
- |
|
5075 |
// Process question versions.
|
- |
|
5076 |
$versiondata = new stdClass();
|
- |
|
5077 |
$versiondata->questionbankentryid = $newentryid;
|
- |
|
5078 |
$versiondata->version = 1;
|
- |
|
5079 |
// Question id is updated after inserting the question.
|
5173 |
'version' => 1,
|
5080 |
$versiondata->questionid = 0;
|
- |
|
5081 |
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
|
5174 |
'status' => $data->hidden ?
|
5082 |
if ((int)$data->hidden === 1) {
|
5175 |
\core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN :
|
5083 |
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
|
- |
|
5084 |
}
|
- |
|
5085 |
$versiondata->status = $versionstatus;
|
- |
|
5086 |
$newversionid = $DB->insert_record('question_versions', $versiondata);
|
5176 |
\core_question\local\bank\question_version_status::QUESTION_STATUS_READY,
|
Línea 5087... |
Línea 5177... |
5087 |
$this->set_mapping('question_version_created', $oldid, $newversionid);
|
5177 |
];
|
5088 |
}
|
5178 |
}
|
5089 |
|
5179 |
|
5090 |
/**
|
5180 |
/**
|
5091 |
* Process question bank entry data.
|
5181 |
* Process question bank entry data.
|
5092 |
*
|
5182 |
*
|
5093 |
* @param array $data the data from the XML file.
|
- |
|
5094 |
*/
|
- |
|
5095 |
protected function process_question_bank_entry($data) {
|
- |
|
5096 |
global $DB;
|
- |
|
5097 |
|
- |
|
5098 |
$data = (object)$data;
|
- |
|
5099 |
$oldid = $data->id;
|
- |
|
5100 |
|
5183 |
* @param array $data the data from the XML file.
|
5101 |
$questioncreated = $this->get_mappingid('question_category_created', $data->questioncategoryid) ? true : false;
|
- |
|
5102 |
$recordexist = $DB->record_exists('question_bank_entries', ['id' => $data->id,
|
- |
|
5103 |
'questioncategoryid' => $data->questioncategoryid]);
|
- |
|
5104 |
// Check we have category created.
|
- |
|
5105 |
if (!$questioncreated && $recordexist) {
|
- |
|
5106 |
return self::SKIP_ALL_CHILDREN;
|
5184 |
*/
|
5107 |
}
|
- |
|
5108 |
|
- |
|
5109 |
$data->questioncategoryid = $this->get_new_parentid('question_category');
|
5185 |
protected function process_question_bank_entry($data) {
|
5110 |
$userid = $this->get_mappingid('user', $data->ownerid);
|
- |
|
5111 |
if ($userid) {
|
- |
|
5112 |
$data->ownerid = $userid;
|
- |
|
5113 |
} else {
|
- |
|
5114 |
if (!$this->task->is_samesite()) {
|
- |
|
5115 |
$data->ownerid = $this->task->get_userid();
|
- |
|
5116 |
}
|
- |
|
5117 |
}
|
- |
|
5118 |
|
- |
|
5119 |
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
- |
|
5120 |
if (!empty($data->idnumber) && $DB->record_exists('question_bank_entries',
|
- |
|
5121 |
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->questioncategoryid])) {
|
- |
|
5122 |
unset($data->idnumber);
|
- |
|
5123 |
}
|
- |
|
5124 |
|
5186 |
// We can only determine the right way to process this once we get to
|
Línea 5125... |
Línea 5187... |
5125 |
$newitemid = $DB->insert_record('question_bank_entries', $data);
|
5187 |
// process_question and have more information, so for now just store.
|
5126 |
$this->set_mapping('question_bank_entry', $oldid, $newitemid);
|
5188 |
$this->latestqbe = (object) $data;
|
5127 |
}
|
5189 |
}
|
5128 |
|
5190 |
|
5129 |
/**
|
5191 |
/**
|
5130 |
* Process question versions.
|
5192 |
* Process question versions.
|
5131 |
*
|
- |
|
5132 |
* @param array $data the data from the XML file.
|
- |
|
5133 |
*/
|
- |
|
5134 |
protected function process_question_versions($data) {
|
- |
|
5135 |
global $DB;
|
- |
|
5136 |
|
5193 |
*
|
5137 |
$data = (object)$data;
|
5194 |
* @param array $data the data from the XML file.
|
5138 |
$oldid = $data->id;
|
- |
|
5139 |
|
- |
|
5140 |
$data->questionbankentryid = $this->get_new_parentid('question_bank_entry');
|
5195 |
*/
|
5141 |
// Question id is updated after inserting the question.
|
5196 |
protected function process_question_versions($data) {
|
Línea 5142... |
Línea 5197... |
5142 |
$data->questionid = 0;
|
5197 |
// We can only determine the right way to process this once we get to
|
5143 |
$newitemid = $DB->insert_record('question_versions', $data);
|
5198 |
// process_question and have more information, so for now just store.
|
5144 |
$this->set_mapping('question_versions', $oldid, $newitemid);
|
5199 |
$this->latestversion = (object) $data;
|
5145 |
}
|
5200 |
}
|
5146 |
|
5201 |
|
5147 |
/**
|
5202 |
/**
|
5148 |
* Process the actual question.
|
5203 |
* Process the actual question.
|
Línea 5149... |
Línea 5204... |
5149 |
*
|
5204 |
*
|
5150 |
* @param array $data the data from the XML file.
|
5205 |
* @param array $data the data from the XML file.
|
Línea 5151... |
Línea 5206... |
5151 |
*/
|
5206 |
*/
|
- |
|
5207 |
protected function process_question($data) {
|
- |
|
5208 |
global $DB;
|
- |
|
5209 |
|
- |
|
5210 |
$data = (object) $data;
|
- |
|
5211 |
$oldid = $data->id;
|
- |
|
5212 |
|
- |
|
5213 |
// Check we have one mapping for this question.
|
5152 |
protected function process_question($data) {
|
5214 |
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
5153 |
global $DB;
|
5215 |
// No mapping = this question doesn't need to be created/mapped.
|
5154 |
|
- |
|
5155 |
$data = (object)$data;
|
- |
|
5156 |
$oldid = $data->id;
|
- |
|
5157 |
|
- |
|
5158 |
// Check if the backup is a pre 4.0 one.
|
- |
|
5159 |
$restoretask = $this->get_task();
|
5216 |
return;
|
5160 |
if ($restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<')) {
|
5217 |
}
|
5161 |
// Check we have one mapping for this question.
|
5218 |
|
5162 |
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
5219 |
// Check if this is a pre 4.0 backup, then there will not be a question bank entry
|
5163 |
return; // No mapping = this question doesn't need to be created/mapped.
|
5220 |
// or question version in the file. So, we need to set up that data ready to be used below.
|
Línea 5204... |
Línea 5261... |
5204 |
if (!$this->task->is_samesite()) {
|
5261 |
if (!$this->task->is_samesite()) {
|
5205 |
$data->modifiedby = $this->task->get_userid();
|
5262 |
$data->modifiedby = $this->task->get_userid();
|
5206 |
}
|
5263 |
}
|
5207 |
}
|
5264 |
}
|
Línea -... |
Línea 5265... |
- |
|
5265 |
|
- |
|
5266 |
// With newitemid = 0, let's create the question.
|
- |
|
5267 |
if (!$questionmapping->newitemid) {
|
- |
|
5268 |
// Now we know we are inserting a question, we may need to insert the questionbankentry.
|
- |
|
5269 |
if (empty($this->latestqbe->newid)) {
|
- |
|
5270 |
$this->latestqbe->oldid = $this->latestqbe->id;
|
- |
|
5271 |
|
- |
|
5272 |
$this->latestqbe->questioncategoryid = $this->get_new_parentid('question_category');
|
- |
|
5273 |
$userid = $this->get_mappingid('user', $this->latestqbe->ownerid);
|
- |
|
5274 |
if ($userid) {
|
- |
|
5275 |
$this->latestqbe->ownerid = $userid;
|
- |
|
5276 |
} else {
|
- |
|
5277 |
if (!$this->task->is_samesite()) {
|
- |
|
5278 |
$this->latestqbe->ownerid = $this->task->get_userid();
|
- |
|
5279 |
}
|
- |
|
5280 |
}
|
- |
|
5281 |
|
- |
|
5282 |
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
- |
|
5283 |
if (!empty($this->latestqbe->idnumber) && $DB->record_exists('question_bank_entries',
|
- |
|
5284 |
['idnumber' => $this->latestqbe->idnumber, 'questioncategoryid' => $this->latestqbe->questioncategoryid])) {
|
- |
|
5285 |
unset($this->latestqbe->idnumber);
|
- |
|
5286 |
}
|
- |
|
5287 |
|
- |
|
5288 |
$this->latestqbe->newid = $DB->insert_record('question_bank_entries', $this->latestqbe);
|
- |
|
5289 |
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
- |
|
5290 |
}
|
- |
|
5291 |
|
5208 |
|
5292 |
// Now store the question.
|
5209 |
$newitemid = $DB->insert_record('question', $data);
|
5293 |
$newitemid = $DB->insert_record('question', $data);
|
5210 |
$this->set_mapping('question', $oldid, $newitemid);
|
5294 |
$this->set_mapping('question', $oldid, $newitemid);
|
5211 |
// Also annotate them as question_created, we need
|
5295 |
// Also annotate them as question_created, we need
|
5212 |
// that later when remapping parents (keeping the old categoryid as parentid).
|
5296 |
// that later when remapping parents (keeping the old categoryid as parentid).
|
5213 |
$parentcatid = $this->get_old_parentid('question_category');
|
5297 |
$parentcatid = $this->get_old_parentid('question_category');
|
- |
|
5298 |
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
5214 |
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
5299 |
|
- |
|
5300 |
// Also insert this question_version.
|
5215 |
// Now update the question_versions table with the new question id. we dont need to do that for random qtypes.
|
5301 |
$oldqvid = $this->latestversion->id;
|
5216 |
$legacyquestiondata = $this->get_mappingid('question_version_created', $oldid) ? true : false;
|
5302 |
$this->latestversion->questionbankentryid = $this->latestqbe->newid;
|
- |
|
5303 |
$this->latestversion->questionid = $newitemid;
|
5217 |
if ($legacyquestiondata) {
|
5304 |
$newqvid = $DB->insert_record('question_versions', $this->latestversion);
|
- |
|
5305 |
$this->set_mapping('question_versions', $oldqvid, $newqvid);
|
5218 |
$parentitemid = $this->get_mappingid('question_version_created', $oldid);
|
5306 |
|
- |
|
5307 |
} else {
|
- |
|
5308 |
// By performing this set_mapping() we make get_old/new_parentid() to work for all the
|
- |
|
5309 |
// children elements of the 'question' one (so qtype plugins will know the question they belong to).
|
- |
|
5310 |
$this->set_mapping('question', $oldid, $questionmapping->newitemid);
|
- |
|
5311 |
|
- |
|
5312 |
// Also create the question_bank_entry and version mappings, if required.
|
5219 |
} else {
|
5313 |
$newquestionversion = $DB->get_record('question_versions', ['questionid' => $questionmapping->newitemid]);
|
- |
|
5314 |
$this->set_mapping('question_versions', $this->latestversion->id, $newquestionversion->id);
|
- |
|
5315 |
if (empty($this->latestqbe->newid)) {
|
- |
|
5316 |
$this->latestqbe->oldid = $this->latestqbe->id;
|
- |
|
5317 |
$this->latestqbe->newid = $newquestionversion->questionbankentryid;
|
- |
|
5318 |
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
5220 |
$parentitemid = $this->get_new_parentid('question_versions');
|
5319 |
}
|
5221 |
}
|
- |
|
5222 |
$version = new stdClass();
|
- |
|
5223 |
$version->id = $parentitemid;
|
- |
|
5224 |
$version->questionid = $newitemid;
|
- |
|
Línea 5225... |
Línea 5320... |
5225 |
$DB->update_record('question_versions', $version);
|
5320 |
}
|
5226 |
|
5321 |
|
5227 |
// Note, we don't restore any question files yet
|
5322 |
// Note, we don't restore any question files yet
|
5228 |
// as far as the CONTEXT_MODULE categories still
|
5323 |
// as far as the CONTEXT_MODULE categories still
|
5229 |
// haven't their contexts to be restored to
|
5324 |
// haven't their contexts to be restored to
|
5230 |
// The {@link restore_create_question_files}, executed in the final step
|
5325 |
// The {@see restore_create_question_files}, executed in the final
|
Línea 5231... |
Línea 5326... |
5231 |
// step will be in charge of restoring all the question files.
|
5326 |
// step will be in charge of restoring all the question files.
|
5232 |
}
|
5327 |
}
|
Línea 5263... |
Línea 5358... |
5263 |
// of all the question's hints in DB as slower fallback. MDL-33863.
|
5358 |
// of all the question's hints in DB as slower fallback. MDL-33863.
|
5264 |
if (!$newitemid) {
|
5359 |
if (!$newitemid) {
|
5265 |
$potentialhints = $DB->get_records('question_hints',
|
5360 |
$potentialhints = $DB->get_records('question_hints',
|
5266 |
array('questionid' => $newquestionid), '', 'id, hint');
|
5361 |
array('questionid' => $newquestionid), '', 'id, hint');
|
5267 |
foreach ($potentialhints as $potentialhint) {
|
5362 |
foreach ($potentialhints as $potentialhint) {
|
5268 |
// Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
|
- |
|
5269 |
$cleanhint = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $potentialhint->hint); // Clean CTRL chars.
|
5363 |
$cleanhint = core_text::trim_ctrl_chars($potentialhint->hint); // Clean CTRL chars.
|
5270 |
$cleanhint = preg_replace("/\r\n|\r/", "\n", $cleanhint); // Normalize line ending.
|
5364 |
$cleanhint = preg_replace("/\r\n|\r/", "\n", $cleanhint); // Normalize line ending.
|
5271 |
if ($cleanhint === $data->hint) {
|
5365 |
if ($cleanhint === $data->hint) {
|
5272 |
$newitemid = $data->id;
|
5366 |
$newitemid = $data->id;
|
5273 |
}
|
5367 |
}
|
5274 |
}
|
5368 |
}
|
Línea 5299... |
Línea 5393... |
5299 |
return;
|
5393 |
return;
|
5300 |
}
|
5394 |
}
|
Línea 5301... |
Línea 5395... |
5301 |
|
5395 |
|
5302 |
if (core_tag_tag::is_enabled('core_question', 'question')) {
|
5396 |
if (core_tag_tag::is_enabled('core_question', 'question')) {
|
5303 |
$tagname = $data->rawname;
|
- |
|
5304 |
if (!empty($data->contextid) && $newcontextid = $this->get_mappingid('context', $data->contextid)) {
|
- |
|
5305 |
$tagcontextid = $newcontextid;
|
- |
|
5306 |
} else {
|
5397 |
$tagname = $data->rawname;
|
5307 |
// Get the category, so we can then later get the context.
|
5398 |
// Get the category, so we can then later get the context.
|
5308 |
$categoryid = $this->get_new_parentid('question_category');
|
5399 |
$categoryid = $this->get_new_parentid('question_category');
|
5309 |
if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) {
|
5400 |
if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) {
|
5310 |
$this->cachedcategory = $DB->get_record('question_categories', array('id' => $categoryid));
|
- |
|
5311 |
}
|
- |
|
5312 |
$tagcontextid = $this->cachedcategory->contextid;
|
5401 |
$this->cachedcategory = $DB->get_record('question_categories', ['id' => $categoryid]);
|
- |
|
5402 |
}
|
5313 |
}
|
5403 |
$tagcontextid = $this->cachedcategory->contextid;
|
5314 |
// Add the tag to the question.
|
5404 |
// Add the tag to the question.
|
- |
|
5405 |
core_tag_tag::add_item_tag('core_question',
|
- |
|
5406 |
'question',
|
5315 |
core_tag_tag::add_item_tag('core_question', 'question', $newquestion,
|
5407 |
$newquestion,
|
5316 |
context::instance_by_id($tagcontextid),
|
5408 |
context::instance_by_id($tagcontextid),
|
- |
|
5409 |
$tagname
|
5317 |
$tagname);
|
5410 |
);
|
5318 |
}
|
5411 |
}
|
Línea 5319... |
Línea 5412... |
5319 |
}
|
5412 |
}
|
5320 |
|
5413 |
|
Línea 5338... |
Línea 5431... |
5338 |
$DB->set_field('question_categories', 'parent', $newparent, array('id' => $dbcat->id));
|
5431 |
$DB->set_field('question_categories', 'parent', $newparent, array('id' => $dbcat->id));
|
5339 |
} else {
|
5432 |
} else {
|
5340 |
$newparent = 0; // No ctx match for both cats, no parent relationship
|
5433 |
$newparent = 0; // No ctx match for both cats, no parent relationship
|
5341 |
}
|
5434 |
}
|
5342 |
}
|
5435 |
}
|
- |
|
5436 |
$context = \core\context::instance_by_id($dbcat->contextid);
|
5343 |
// Here with $newparent empty, problem with contexts or remapping, set it to top cat
|
5437 |
// Here with $newparent empty, problem with contexts or remapping, set it to top cat
|
5344 |
if (!$newparent && $dbcat->parent) {
|
5438 |
if (!$newparent && $dbcat->parent && $context->contextlevel === CONTEXT_MODULE) {
|
5345 |
$topcat = question_get_top_category($dbcat->contextid, true);
|
5439 |
$topcat = question_get_top_category($dbcat->contextid, true);
|
5346 |
if ($dbcat->parent != $topcat->id) {
|
5440 |
if ($dbcat->parent != $topcat->id) {
|
5347 |
$DB->set_field('question_categories', 'parent', $topcat->id, array('id' => $dbcat->id));
|
5441 |
$DB->set_field('question_categories', 'parent', $topcat->id, array('id' => $dbcat->id));
|
5348 |
}
|
5442 |
}
|
5349 |
}
|
5443 |
}
|
Línea 5384... |
Línea 5478... |
5384 |
|
5478 |
|
Línea 5385... |
Línea 5479... |
5385 |
$after35 = $this->task->backup_release_compare('3.5', '>=') && $this->task->backup_version_compare(20180205, '>');
|
5479 |
$after35 = $this->task->backup_release_compare('3.5', '>=') && $this->task->backup_version_compare(20180205, '>');
|
5386 |
|
5480 |
|
- |
|
5481 |
$contexts = restore_dbops::restore_get_question_banks($this->get_restoreid(), CONTEXT_MODULE);
|
- |
|
5482 |
foreach ($contexts as $contextid => $contextlevel) {
|
5387 |
$contexts = restore_dbops::restore_get_question_banks($this->get_restoreid(), CONTEXT_MODULE);
|
5483 |
if (!$newcontext = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $contextid)) {
|
- |
|
5484 |
// The bank for the question categories required by this module was not included in the backup,
|
5388 |
foreach ($contexts as $contextid => $contextlevel) {
|
5485 |
// but if that context still exists on the site and the user has access then point question references
|
5389 |
// Only if context mapping exists (i.e. the module has been restored)
|
5486 |
// to the originals.
|
5390 |
if ($newcontext = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $contextid)) {
|
5487 |
$originalcontext = context::instance_by_id($contextid, IGNORE_MISSING);
|
5391 |
// Update all the qcats having their parentitemid set to the original contextid
|
5488 |
if ($originalcontext && has_capability('mod/qbank:view', $originalcontext)) {
|
5392 |
$modulecats = $DB->get_records_sql("SELECT itemid, newitemid, info
|
5489 |
$originalquestions = get_questions_category(question_get_top_category($contextid), false);
|
5393 |
FROM {backup_ids_temp}
|
5490 |
$targetcoursecontext = context_course::instance($this->get_courseid());
|
5394 |
WHERE backupid = ?
|
5491 |
foreach ($originalquestions as $originalquestion) {
|
- |
|
5492 |
$backupids = restore_dbops::get_backup_ids_record(
|
5395 |
AND itemname = 'question_category'
|
5493 |
$this->get_restoreid(),
|
5396 |
AND parentitemid = ?", array($this->get_restoreid(), $contextid));
|
5494 |
'question',
|
5397 |
$top = question_get_top_category($newcontext->newitemid, true);
|
5495 |
$originalquestion->id,
|
- |
|
5496 |
);
|
5398 |
$oldtopid = 0;
|
5497 |
if (!$backupids) {
|
5399 |
$categoryids = [];
|
5498 |
continue; // This question was not included in the backup.
|
5400 |
foreach ($modulecats as $modulecat) {
|
5499 |
}
|
- |
|
5500 |
// Restored question references will point to the restored copy of the question. Select question references
|
5401 |
// Before 3.5, question categories could be created at top level.
|
5501 |
// that point to that restored copy, only if they are within the target course's context, so we can update
|
5402 |
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
5502 |
// them to point to the original question.
|
5403 |
$info = backup_controller_dbops::decode_backup_temp_info($modulecat->info);
|
5503 |
$conpathlike = $DB->sql_like('con.path', '?');
|
5404 |
if ($after35 && empty($info->parent)) {
|
5504 |
$references = $DB->get_records_sql(
|
- |
|
5505 |
"SELECT qr.id, qr.questionbankentryid
|
- |
|
5506 |
FROM {question_references} qr
|
5405 |
$oldtopid = $modulecat->newitemid;
|
5507 |
JOIN {context} con ON qr.usingcontextid = con.id
|
- |
|
5508 |
JOIN {question_versions} qv ON qv.questionbankentryid = qr.questionbankentryid
|
5406 |
$modulecat->newitemid = $top->id;
|
5509 |
WHERE qv.questionid = ?
|
5407 |
} else {
|
5510 |
AND {$conpathlike}",
|
5408 |
$cat = new stdClass();
|
5511 |
[
|
- |
|
5512 |
$backupids->newitemid,
|
- |
|
5513 |
$targetcoursecontext->path . '/%',
|
5409 |
$cat->id = $modulecat->newitemid;
|
5514 |
],
|
5410 |
$cat->contextid = $newcontext->newitemid;
|
5515 |
);
|
5411 |
if (empty($info->parent)) {
|
5516 |
if (empty($references)) {
|
- |
|
5517 |
continue;
|
- |
|
5518 |
}
|
5412 |
$cat->parent = $top->id;
|
5519 |
[$refin, $refparams] = $DB->get_in_or_equal(array_keys($references));
|
- |
|
5520 |
$DB->set_field_select(
|
- |
|
5521 |
'question_references',
|
5413 |
}
|
5522 |
'questionbankentryid',
|
- |
|
5523 |
$DB->get_field('question_versions', 'questionbankentryid', ['questionid' => $backupids->itemid]),
|
- |
|
5524 |
'id ' . $refin,
|
5414 |
$DB->update_record('question_categories', $cat);
|
5525 |
$refparams,
|
- |
|
5526 |
);
|
- |
|
5527 |
}
|
- |
|
5528 |
continue;
|
- |
|
5529 |
}
|
- |
|
5530 |
// We have no target question bank so create a default bank for categories without a module to attach to.
|
- |
|
5531 |
// This can occur when a quiz backup contains references to a question bank module,
|
- |
|
5532 |
// that was not included in the backup and does not exist in the site being restored to.
|
- |
|
5533 |
$course = get_course($this->get_courseid());
|
- |
|
5534 |
$defaultqbank = core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
|
- |
|
5535 |
$context = context_module::instance($defaultqbank->id);
|
5415 |
$categoryids[] = (int)$cat->id;
|
5536 |
$newcontext = new stdClass();
|
- |
|
5537 |
$newcontext->newitemid = $context->id;
|
- |
|
5538 |
}
|
- |
|
5539 |
// Only if context mapping exists (i.e. the module has been restored)
|
- |
|
5540 |
// Update all the qcats having their parentitemid set to the original contextid.
|
- |
|
5541 |
$modulecats = $DB->get_records_sql("SELECT itemid, newitemid, info
|
5416 |
}
|
5542 |
FROM {backup_ids_temp}
|
5417 |
|
5543 |
WHERE backupid = ?
|
- |
|
5544 |
AND itemname = 'question_category'
|
- |
|
5545 |
AND parentitemid = ?",
|
- |
|
5546 |
[$this->get_restoreid(), $contextid]
|
- |
|
5547 |
);
|
- |
|
5548 |
$top = question_get_top_category($newcontext->newitemid, true);
|
- |
|
5549 |
$oldtopid = 0;
|
- |
|
5550 |
$categoryids = [];
|
5418 |
// And set new contextid (and maybe update newitemid) also in question_category mapping (will be
|
5551 |
foreach ($modulecats as $modulecat) {
|
- |
|
5552 |
// Before 3.5, question categories could be created at top level.
|
- |
|
5553 |
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
- |
|
5554 |
$info = backup_controller_dbops::decode_backup_temp_info($modulecat->info);
|
- |
|
5555 |
if ($after35 && empty($info->parent)) {
|
- |
|
5556 |
$oldtopid = $modulecat->newitemid;
|
- |
|
5557 |
$modulecat->newitemid = $top->id;
|
- |
|
5558 |
} else {
|
5419 |
// used by {@link restore_create_question_files} later.
|
5559 |
$cat = new stdClass();
|
- |
|
5560 |
$cat->id = $modulecat->newitemid;
|
- |
|
5561 |
$cat->contextid = $newcontext->newitemid;
|
- |
|
5562 |
if (empty($info->parent)) {
|
- |
|
5563 |
$cat->parent = $top->id;
|
- |
|
5564 |
}
|
5420 |
restore_dbops::set_backup_ids_record($this->get_restoreid(), 'question_category', $modulecat->itemid,
|
5565 |
$DB->update_record('question_categories', $cat);
|
Línea -... |
Línea 5566... |
- |
|
5566 |
$categoryids[] = (int) $cat->id;
|
- |
|
5567 |
}
|
- |
|
5568 |
|
- |
|
5569 |
// And set new contextid (and maybe update newitemid) also in question_category mapping (will be
|
- |
|
5570 |
// used by {@see restore_create_question_files} later.
|
- |
|
5571 |
restore_dbops::set_backup_ids_record($this->get_restoreid(),
|
- |
|
5572 |
'question_category',
|
- |
|
5573 |
$modulecat->itemid,
|
- |
|
5574 |
$modulecat->newitemid,
|
- |
|
5575 |
$newcontext->newitemid
|
5421 |
$modulecat->newitemid, $newcontext->newitemid);
|
5576 |
);
|
5422 |
}
|
5577 |
}
|
5423 |
|
5578 |
|
5424 |
// Update the context id of any tags applied to any questions in these categories.
|
5579 |
// Update the context id of any tags applied to any questions in these categories.
|
5425 |
if ($categoryids) {
|
5580 |
if ($categoryids) {
|
5426 |
[$categorysql, $categoryidparams] = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
|
5581 |
[$categorysql, $categoryidparams] = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED);
|
5427 |
$sqlupdate = "UPDATE {tag_instance}
|
5582 |
$sqlupdate = "UPDATE {tag_instance}
|
5428 |
SET contextid = :newcontext
|
5583 |
SET contextid = :newcontext
|
5429 |
WHERE component = :component
|
5584 |
WHERE component = :component
|
5430 |
AND itemtype = :itemtype
|
5585 |
AND itemtype = :itemtype
|
5431 |
AND itemid IN (SELECT DISTINCT bi.newitemid as questionid
|
5586 |
AND itemid IN (SELECT DISTINCT bi.newitemid as questionid
|
5432 |
FROM {backup_ids_temp} bi
|
5587 |
FROM {backup_ids_temp} bi
|
5433 |
JOIN {question} q ON q.id = bi.newitemid
|
5588 |
JOIN {question} q ON q.id = bi.newitemid
|
5434 |
JOIN {question_versions} qv ON qv.questionid = q.id
|
5589 |
JOIN {question_versions} qv ON qv.questionid = q.id
|
5435 |
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
|
5590 |
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
|
5436 |
WHERE bi.backupid = :backupid AND bi.itemname = 'question_created'
|
5591 |
WHERE bi.backupid = :backupid AND bi.itemname = 'question_created'
|
5437 |
AND qbe.questioncategoryid {$categorysql}) ";
|
5592 |
AND qbe.questioncategoryid {$categorysql}) ";
|
5438 |
$params = [
|
5593 |
$params = [
|
5439 |
'newcontext' => $newcontext->newitemid,
|
5594 |
'newcontext' => $newcontext->newitemid,
|
5440 |
'component' => 'core_question',
|
5595 |
'component' => 'core_question',
|
5441 |
'itemtype' => 'question',
|
5596 |
'itemtype' => 'question',
|
5442 |
'backupid' => $this->get_restoreid(),
|
5597 |
'backupid' => $this->get_restoreid(),
|
5443 |
];
|
5598 |
];
|
5444 |
$params += $categoryidparams;
|
5599 |
$params += $categoryidparams;
|
5445 |
$DB->execute($sqlupdate, $params);
|
5600 |
$DB->execute($sqlupdate, $params);
|
5446 |
|
5601 |
|
5447 |
// As explained in {@see restore_quiz_activity_structure_step::process_quiz_question_legacy_instance()}
|
5602 |
// As explained in {@see restore_quiz_activity_structure_step::process_quiz_question_legacy_instance()}
|
5448 |
// question_set_references relating to random questions restored from old backups,
|
5603 |
// question_set_references relating to random questions restored from old backups,
|
5449 |
// which pick from context_module question_categores, will have been restored with the wrong questioncontextid.
|
5604 |
// which pick from context_module question_categores, will have been restored with the wrong questioncontextid.
|
5450 |
// So, now, we need to find those, and updated the questioncontextid.
|
5605 |
// So, now, we need to find those, and updated the questioncontextid.
|
5451 |
// We can only find them by picking apart the filter conditions, and seeign which categories they refer to.
|
5606 |
// We can only find them by picking apart the filter conditions, and seeign which categories they refer to.
|
5452 |
|
5607 |
|
5453 |
// We need to check all the question_set_references belonging to this context_module.
|
5608 |
// We need to check all the question_set_references belonging to this context_module.
|
5454 |
$references = $DB->get_records('question_set_references', ['usingcontextid' => $newcontext->newitemid]);
|
5609 |
$references = $DB->get_records('question_set_references', ['usingcontextid' => $newcontext->newitemid]);
|
5455 |
foreach ($references as $reference) {
|
5610 |
foreach ($references as $reference) {
|
5456 |
$filtercondition = json_decode($reference->filtercondition);
|
5611 |
$filtercondition = json_decode($reference->filtercondition);
|
5457 |
if (!empty($filtercondition->questioncategoryid) &&
|
5612 |
if (!empty($filtercondition->questioncategoryid) &&
|
5458 |
in_array($filtercondition->questioncategoryid, $categoryids)) {
|
5613 |
in_array($filtercondition->questioncategoryid, $categoryids)) {
|
5459 |
// This is one of ours, update the questionscontextid.
|
5614 |
// This is one of ours, update the questionscontextid.
|
5460 |
$DB->set_field('question_set_references',
|
- |
|
5461 |
'questionscontextid', $newcontext->newitemid,
|
5615 |
$DB->set_field('question_set_references',
|
5462 |
['id' => $reference->id]);
|
5616 |
'questionscontextid', $newcontext->newitemid,
|
- |
|
5617 |
['id' => $reference->id]);
|
Línea 5463... |
Línea 5618... |
5463 |
}
|
5618 |
}
|
5464 |
}
|
5619 |
}
|
5465 |
}
|
5620 |
}
|
5466 |
|
5621 |
|
- |
|
5622 |
// Now set the parent id for the question categories that were in the top category in the course context
|
- |
|
5623 |
// and have been moved now.
|
5467 |
// Now set the parent id for the question categories that were in the top category in the course context
|
5624 |
if ($oldtopid) {
|
5468 |
// and have been moved now.
|
5625 |
$DB->set_field('question_categories',
|
5469 |
if ($oldtopid) {
|
5626 |
'parent',
|
5470 |
$DB->set_field('question_categories', 'parent', $top->id,
|
5627 |
$top->id,
|
- |
|
5628 |
['contextid' => $newcontext->newitemid, 'parent' => $oldtopid]
|
- |
|
5629 |
);
|
- |
|
5630 |
}
|
- |
|
5631 |
}
|
- |
|
5632 |
// Remove any remaining course-level question categories from the restored course.
|
- |
|
5633 |
$coursecatsql = "
|
- |
|
5634 |
SELECT qc.id AS categoryid
|
- |
|
5635 |
FROM {question_categories} qc
|
- |
|
5636 |
JOIN {context} c ON c.id = qc.contextid
|
- |
|
5637 |
WHERE c.contextlevel = :courselevel AND c.instanceid = :courseid
|
- |
|
5638 |
";
|
- |
|
5639 |
$DB->delete_records_subquery(
|
- |
|
5640 |
'question_categories',
|
- |
|
5641 |
'id',
|
5471 |
array('contextid' => $newcontext->newitemid, 'parent' => $oldtopid));
|
5642 |
'categoryid',
|
5472 |
}
|
5643 |
$coursecatsql,
|
Línea 5473... |
Línea 5644... |
5473 |
}
|
5644 |
['courselevel' => context_course::LEVEL, 'courseid' => $this->task->get_courseid()]
|
5474 |
}
|
5645 |
);
|
Línea 6248... |
Línea 6419... |
6248 |
* @param array $data the data from the XML file.
|
6419 |
* @param array $data the data from the XML file.
|
6249 |
*/
|
6420 |
*/
|
6250 |
public function process_question_set_reference($data) {
|
6421 |
public function process_question_set_reference($data) {
|
6251 |
global $DB;
|
6422 |
global $DB;
|
6252 |
$data = (object) $data;
|
6423 |
$data = (object) $data;
|
- |
|
6424 |
$owncontext = $data->usingcontextid == $data->questionscontextid;
|
6253 |
$data->usingcontextid = $this->get_mappingid('context', $data->usingcontextid);
|
6425 |
$data->usingcontextid = $this->get_mappingid('context', $data->usingcontextid);
|
6254 |
$data->itemid = $this->get_new_parentid('quiz_question_instance');
|
6426 |
$data->itemid = $this->get_new_parentid('quiz_question_instance');
|
6255 |
$filtercondition = json_decode($data->filtercondition, true);
|
6427 |
$filtercondition = json_decode($data->filtercondition, true);
|
Línea 6256... |
Línea 6428... |
6256 |
|
6428 |
|
Línea 6260... |
Línea 6432... |
6260 |
$filtercondition);
|
6432 |
$filtercondition);
|
6261 |
}
|
6433 |
}
|
Línea 6262... |
Línea 6434... |
6262 |
|
6434 |
|
6263 |
// Map category id used for category filter condition and corresponding context id.
|
6435 |
// Map category id used for category filter condition and corresponding context id.
|
- |
|
6436 |
$oldcategoryid = $filtercondition['filter']['category']['values'][0];
|
- |
|
6437 |
// Decide if we're going to refer back to the original category, or to the new category.
|
- |
|
6438 |
// Are we restoring to a different site?
|
- |
|
6439 |
// Has the original context or category been deleted?
|
- |
|
6440 |
// Did the old category belong to the same context as the original set reference?
|
- |
|
6441 |
// Are we allowed to use its questions?
|
- |
|
6442 |
$questionscontext = context::instance_by_id($data->questionscontextid, IGNORE_MISSING);
|
- |
|
6443 |
if (
|
- |
|
6444 |
!$this->get_task()->is_samesite()
|
- |
|
6445 |
|| !$questionscontext
|
- |
|
6446 |
|| !$DB->record_exists('question_categories', ['id' => $oldcategoryid])
|
- |
|
6447 |
|| $owncontext
|
- |
|
6448 |
|| !has_capability('moodle/question:useall', $questionscontext)
|
6264 |
$oldcategoryid = $filtercondition['filter']['category']['values'][0];
|
6449 |
) {
|
6265 |
$newcategoryid = $this->get_mappingid('question_category', $oldcategoryid);
|
6450 |
$newcategoryid = $this->get_mappingid('question_category', $oldcategoryid);
|
- |
|
6451 |
$filtercondition['filter']['category']['values'][0] = $newcategoryid;
|
Línea 6266... |
Línea 6452... |
6266 |
$filtercondition['filter']['category']['values'][0] = $newcategoryid;
|
6452 |
}
|
6267 |
|
6453 |
|
6268 |
if ($context = $this->get_mappingid('context', $data->questionscontextid)) {
|
6454 |
if ($context = $this->get_mappingid('context', $data->questionscontextid)) {
|
6269 |
$data->questionscontextid = $context;
|
6455 |
$data->questionscontextid = $context;
|