mirror of
https://github.com/moodle/moodle.git
synced 2025-04-19 07:25:30 +02:00
MDL-77625 question restore: fix restore of existing questions
Continuing from the last commit, the code to restore question bank entries, versions and questions, was not taking note of whether the first stage had indentified questions that did not need to be restored. This is tricky, but the mapping can only be worked out for questions, but in the backup file, the questions are inside the question_bank_entries, and versions, so we encounter those first. Now, the code just saves the QBE and QV when it encounters them, and then does all the processing when it gets to the question, correctly taking note of whether each question should be restored or not. In cases where a particular question does not need to be restored, we still set up the corresponding mappings.
This commit is contained in:
parent
bab665dd40
commit
c248dee33c
@ -5006,6 +5006,12 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
/** @var array $cachedcategory store a question category */
|
||||
protected $cachedcategory = null;
|
||||
|
||||
/** @var stdClass the last question_bank_entry seen during the restore. Processed when we get to a question. */
|
||||
protected $latestqbe;
|
||||
|
||||
/** @var stdClass the last question_version seen during the restore. Processed when we get to a question. */
|
||||
protected $latestversion;
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
@ -5131,45 +5137,25 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
}
|
||||
|
||||
/**
|
||||
* Process pre 4.0 question data where in creates the record for version and entry table.
|
||||
* Set up date to allow restore of questions from pre-4.0 backups.
|
||||
*
|
||||
* @param array $data the data from the XML file.
|
||||
* @param stdClass $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_legacy_data($data) {
|
||||
global $DB;
|
||||
$this->latestqbe = (object) [
|
||||
'id' => $data->id,
|
||||
'questioncategoryid' => $data->category,
|
||||
'ownerid' => $data->createdby,
|
||||
'idnumber' => $data->idnumber ?? null,
|
||||
];
|
||||
|
||||
$oldid = $data->id;
|
||||
// Process question bank entry.
|
||||
$entrydata = new stdClass();
|
||||
$entrydata->questioncategoryid = $data->category;
|
||||
$userid = $this->get_mappingid('user', $data->createdby);
|
||||
if ($userid) {
|
||||
$entrydata->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$entrydata->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (isset($data->idnumber) && !$DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->category])) {
|
||||
$entrydata->idnumber = $data->idnumber;
|
||||
}
|
||||
|
||||
$newentryid = $DB->insert_record('question_bank_entries', $entrydata);
|
||||
// Process question versions.
|
||||
$versiondata = new stdClass();
|
||||
$versiondata->questionbankentryid = $newentryid;
|
||||
$versiondata->version = 1;
|
||||
// Question id is updated after inserting the question.
|
||||
$versiondata->questionid = 0;
|
||||
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
|
||||
if ((int)$data->hidden === 1) {
|
||||
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
|
||||
}
|
||||
$versiondata->status = $versionstatus;
|
||||
$newversionid = $DB->insert_record('question_versions', $versiondata);
|
||||
$this->set_mapping('question_version_created', $oldid, $newversionid);
|
||||
$this->latestversion = (object) [
|
||||
'id' => $data->id,
|
||||
'version' => 1,
|
||||
'status' => $data->hidden ?
|
||||
\core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN :
|
||||
\core_question\local\bank\question_version_status::QUESTION_STATUS_READY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5178,37 +5164,9 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
* @param array $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_bank_entry($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$questioncreated = $this->get_mappingid('question_category_created', $data->questioncategoryid) ? true : false;
|
||||
$recordexist = $DB->record_exists('question_bank_entries', ['id' => $data->id,
|
||||
'questioncategoryid' => $data->questioncategoryid]);
|
||||
// Check we have category created.
|
||||
if (!$questioncreated && $recordexist) {
|
||||
return self::SKIP_ALL_CHILDREN;
|
||||
}
|
||||
|
||||
$data->questioncategoryid = $this->get_new_parentid('question_category');
|
||||
$userid = $this->get_mappingid('user', $data->ownerid);
|
||||
if ($userid) {
|
||||
$data->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$data->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (!empty($data->idnumber) && $DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->questioncategoryid])) {
|
||||
unset($data->idnumber);
|
||||
}
|
||||
|
||||
$newitemid = $DB->insert_record('question_bank_entries', $data);
|
||||
$this->set_mapping('question_bank_entry', $oldid, $newitemid);
|
||||
// We can only determine the right way to process this once we get to
|
||||
// process_question and have more information, so for now just store.
|
||||
$this->latestqbe = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5217,16 +5175,9 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
* @param array $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_versions($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$data->questionbankentryid = $this->get_new_parentid('question_bank_entry');
|
||||
// Question id is updated after inserting the question.
|
||||
$data->questionid = 0;
|
||||
$newitemid = $DB->insert_record('question_versions', $data);
|
||||
$this->set_mapping('question_versions', $oldid, $newitemid);
|
||||
// We can only determine the right way to process this once we get to
|
||||
// process_question and have more information, so for now just store.
|
||||
$this->latestversion = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5237,17 +5188,19 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
protected function process_question($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$data = (object) $data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
// No mapping = this question doesn't need to be created/mapped.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a pre 4.0 backup, then there will not be a question bank entry
|
||||
// or question version in the file. So, we need to set up that data ready to be used below.
|
||||
$restoretask = $this->get_task();
|
||||
if ($restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<')) {
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
return; // No mapping = this question doesn't need to be created/mapped.
|
||||
}
|
||||
|
||||
// Get the mapped category (cannot use get_new_parentid() because not
|
||||
// all the categories have been created, so it is not always available
|
||||
// Instead we get the mapping for the question->parentitemid because
|
||||
@ -5291,28 +5244,66 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
}
|
||||
}
|
||||
|
||||
$newitemid = $DB->insert_record('question', $data);
|
||||
$this->set_mapping('question', $oldid, $newitemid);
|
||||
// Also annotate them as question_created, we need
|
||||
// that later when remapping parents (keeping the old categoryid as parentid).
|
||||
$parentcatid = $this->get_old_parentid('question_category');
|
||||
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
||||
// Now update the question_versions table with the new question id. we dont need to do that for random qtypes.
|
||||
$legacyquestiondata = $this->get_mappingid('question_version_created', $oldid) ? true : false;
|
||||
if ($legacyquestiondata) {
|
||||
$parentitemid = $this->get_mappingid('question_version_created', $oldid);
|
||||
// With newitemid = 0, let's create the question.
|
||||
if (!$questionmapping->newitemid) {
|
||||
// Now we know we are inserting a question, we may need to insert the questionbankentry.
|
||||
if (empty($this->latestqbe->newid)) {
|
||||
$this->latestqbe->oldid = $this->latestqbe->id;
|
||||
|
||||
$this->latestqbe->questioncategoryid = $this->get_new_parentid('question_category');
|
||||
$userid = $this->get_mappingid('user', $this->latestqbe->ownerid);
|
||||
if ($userid) {
|
||||
$this->latestqbe->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$this->latestqbe->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (!empty($this->latestqbe->idnumber) && $DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $this->latestqbe->idnumber, 'questioncategoryid' => $this->latestqbe->questioncategoryid])) {
|
||||
unset($this->latestqbe->idnumber);
|
||||
}
|
||||
|
||||
$this->latestqbe->newid = $DB->insert_record('question_bank_entries', $this->latestqbe);
|
||||
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
||||
}
|
||||
|
||||
// Now store the question.
|
||||
$newitemid = $DB->insert_record('question', $data);
|
||||
$this->set_mapping('question', $oldid, $newitemid);
|
||||
// Also annotate them as question_created, we need
|
||||
// that later when remapping parents (keeping the old categoryid as parentid).
|
||||
$parentcatid = $this->get_old_parentid('question_category');
|
||||
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
||||
|
||||
// Also insert this question_version.
|
||||
$oldqvid = $this->latestversion->id;
|
||||
$this->latestversion->questionbankentryid = $this->latestqbe->newid;
|
||||
$this->latestversion->questionid = $newitemid;
|
||||
$newqvid = $DB->insert_record('question_versions', $this->latestversion);
|
||||
$this->set_mapping('question_versions', $oldqvid, $newqvid);
|
||||
|
||||
} else {
|
||||
$parentitemid = $this->get_new_parentid('question_versions');
|
||||
// By performing this set_mapping() we make get_old/new_parentid() to work for all the
|
||||
// children elements of the 'question' one (so qtype plugins will know the question they belong to).
|
||||
$this->set_mapping('question', $oldid, $questionmapping->newitemid);
|
||||
|
||||
// Also create the question_bank_entry and version mappings, if required.
|
||||
$newquestionversion = $DB->get_record('question_versions', ['questionid' => $questionmapping->newitemid]);
|
||||
$this->set_mapping('question_versions', $this->latestversion->id, $newquestionversion->id);
|
||||
if (empty($this->latestqbe->newid)) {
|
||||
$this->latestqbe->oldid = $this->latestqbe->id;
|
||||
$this->latestqbe->newid = $newquestionversion->questionbankentryid;
|
||||
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
||||
}
|
||||
}
|
||||
$version = new stdClass();
|
||||
$version->id = $parentitemid;
|
||||
$version->questionid = $newitemid;
|
||||
$DB->update_record('question_versions', $version);
|
||||
|
||||
// Note, we don't restore any question files yet
|
||||
// as far as the CONTEXT_MODULE categories still
|
||||
// haven't their contexts to be restored to
|
||||
// The {@link restore_create_question_files}, executed in the final step
|
||||
// The {@see restore_create_question_files}, executed in the final
|
||||
// step will be in charge of restoring all the question files.
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user