mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 07:56:06 +02:00
MDL-61614 Quiz: Restore tags for random questions
This commit is contained in:
parent
2a1855887d
commit
9da6f4d968
@ -59,6 +59,8 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
|
||||
$paths[] = new restore_path_element('quiz_question_instance',
|
||||
'/activity/quiz/question_instances/question_instance');
|
||||
$paths[] = new restore_path_element('quiz_slot_tags',
|
||||
'/activity/quiz/question_instances/question_instance/tags/tag');
|
||||
$paths[] = new restore_path_element('quiz_section', '/activity/quiz/sections/section');
|
||||
$paths[] = new restore_path_element('quiz_feedback', '/activity/quiz/feedbacks/feedback');
|
||||
$paths[] = new restore_path_element('quiz_override', '/activity/quiz/overrides/override');
|
||||
@ -254,6 +256,7 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
global $CFG, $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Backwards compatibility for old field names (MDL-43670).
|
||||
if (!isset($data->questionid) && isset($data->question)) {
|
||||
@ -301,14 +304,32 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
$data->includingsubcategories = $questionmapping->info->questiontext ? 1 : 0;
|
||||
}
|
||||
|
||||
if (isset($data->tags)) {
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
$newitemid = $DB->insert_record('quiz_slots', $data);
|
||||
// Add mapping, restore of slot tags (for random questions) need it.
|
||||
$this->set_mapping('quiz_question_instance', $oldid, $newitemid);
|
||||
}
|
||||
|
||||
$tags = quiz_extract_random_question_tags($data->tags, $this->task->is_samesite());
|
||||
$data->tags = quiz_build_random_question_tag_json($tags);
|
||||
/**
|
||||
* Process a quiz_slot_tags restore
|
||||
*
|
||||
* @param stdClass|array $data The quiz_slot_tags data
|
||||
*/
|
||||
protected function process_quiz_slot_tags($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
|
||||
$data->slotid = $this->get_new_parentid('quiz_question_instance');
|
||||
if ($this->task->is_samesite() && $tag = core_tag_tag::get($data->tagid, 'id, name')) {
|
||||
$data->tagname = $tag->name;
|
||||
} else if ($tag = core_tag_tag::get_by_name(0, $data->tagname, 'id, name')) {
|
||||
$data->tagid = $tag->id;
|
||||
} else {
|
||||
$data->tagid = null;
|
||||
$data->tagname = $tag->name;
|
||||
}
|
||||
|
||||
$DB->insert_record('quiz_slots', $data);
|
||||
$DB->insert_record('quiz_slot_tags', $data);
|
||||
}
|
||||
|
||||
protected function process_quiz_section($data) {
|
||||
|
@ -2431,68 +2431,6 @@ function quiz_is_overriden_calendar_event(\calendar_event $event) {
|
||||
return $DB->record_exists('quiz_overrides', $overrideparams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Providing a list of tag records, this function validates each pair and builds a json string
|
||||
* that can be stored in the quiz_slots.tags field.
|
||||
*
|
||||
* @param stdClass[] $tagrecords List of tag objects with id and name properties.
|
||||
* @return string
|
||||
*/
|
||||
function quiz_build_random_question_tag_json($tagrecords) {
|
||||
$tags = [];
|
||||
foreach ($tagrecords as $tagrecord) {
|
||||
if ($tagrecord->id && $tag = core_tag_tag::get($tagrecord->id, 'id, name')) {
|
||||
$tags[] = [
|
||||
'id' => (int)$tagrecord->id,
|
||||
'name' => $tag->name
|
||||
];
|
||||
} else if ($tag = core_tag_tag::get_by_name(0, $tagrecord->name, 'id, name')) {
|
||||
$tags[] = [
|
||||
'id' => (int)$tag->id,
|
||||
'name' => $tagrecord->name
|
||||
];
|
||||
} else {
|
||||
$tags[] = [
|
||||
'id' => null,
|
||||
'name' => $tagrecord->name
|
||||
];
|
||||
}
|
||||
}
|
||||
return json_encode($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Providing tags data in the JSON format, this function returns tag records containing the id and name properties.
|
||||
*
|
||||
* @param string $tagsjson The JSON string representing an array of tags in the [{"id":tagid,"name":"tagname"}] format.
|
||||
* E.g. [{"id":1,"name":"tag1"},{"id":2,"name":"tag2"}]
|
||||
* Usually equal to the value of the tags field retrieved from the quiz_slots table.
|
||||
* @param bool $matchbyid If set to true, then the function tries to find tags by their id.
|
||||
* If no tag is found by the tag id or if $matchbyid is set to false, then the function tries to find the tag by its name.
|
||||
* @return array An array of tags containing the id and name properties, indexed by tag ids.
|
||||
*/
|
||||
function quiz_extract_random_question_tags($tagsjson, $matchbyid = true) {
|
||||
$tagrecords = [];
|
||||
if (!empty($tagsjson)) {
|
||||
$tags = json_decode($tagsjson);
|
||||
|
||||
foreach ($tags as $tagdata) {
|
||||
if ($matchbyid && $tag = core_tag_tag::get($tagdata->id, 'id, name')) {
|
||||
$tagrecords[] = $tag->to_object();
|
||||
} else if ($tag = core_tag_tag::get_by_name(0, $tagdata->name, 'id, name')) {
|
||||
$tagrecords[] = $tag->to_object();
|
||||
} else {
|
||||
$tagrecords[] = (object)[
|
||||
'id' => null,
|
||||
'name' => $tagdata->name
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tagrecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves tag information for the given quiz slot.
|
||||
* A quiz slot have some tags if and only if it is representing a random question by tags.
|
||||
|
BIN
mod/quiz/tests/fixtures/random_by_tag_quiz.mbz
vendored
BIN
mod/quiz/tests/fixtures/random_by_tag_quiz.mbz
vendored
Binary file not shown.
@ -421,153 +421,6 @@ class mod_quiz_locallib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
|
||||
}
|
||||
|
||||
public function test_quiz_build_random_question_tag_json() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Setup test data.
|
||||
$footagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'foo',
|
||||
'description' => 'foo desc'
|
||||
);
|
||||
$footag = $this->getDataGenerator()->create_tag($footagrecord);
|
||||
$bartagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'bar',
|
||||
'description' => 'bar desc'
|
||||
);
|
||||
$bartag = $this->getDataGenerator()->create_tag($bartagrecord);
|
||||
$baztagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'baz',
|
||||
'description' => 'baz desc'
|
||||
);
|
||||
$baztag = $this->getDataGenerator()->create_tag($baztagrecord);
|
||||
$quxtagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'qux',
|
||||
'description' => 'qux desc'
|
||||
);
|
||||
$quxtag = $this->getDataGenerator()->create_tag($quxtagrecord);
|
||||
$quuxtagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'quux',
|
||||
'description' => 'quux desc'
|
||||
);
|
||||
$quuxtag = $this->getDataGenerator()->create_tag($quuxtagrecord);
|
||||
|
||||
$tagrecords = array(
|
||||
(object)[
|
||||
'id' => $footag->id,
|
||||
'name' => 'foo'
|
||||
],
|
||||
(object)[
|
||||
'id' => 999, // An invalid tag id.
|
||||
'name' => 'bar'
|
||||
],
|
||||
(object)[
|
||||
'id' => null,
|
||||
'name' => 'baz'
|
||||
],
|
||||
(object)[
|
||||
'id' => $quxtag->id,
|
||||
'name' => 'invalidqux' // An invalid tag name.
|
||||
],
|
||||
(object)[
|
||||
'id' => 999, // An invalid tag id.
|
||||
'name' => 'invalidquux' // An invalid tag name.
|
||||
],
|
||||
);
|
||||
|
||||
$expectedjson = json_encode(array(
|
||||
['id' => (int)$footag->id, 'name' => $footag->name],
|
||||
['id' => (int)$bartag->id, 'name' => $bartag->name],
|
||||
['id' => (int)$baztag->id, 'name' => $baztag->name],
|
||||
['id' => (int)$quxtag->id, 'name' => $quxtag->name],
|
||||
['id' => null, 'name' => 'invalidquux'],
|
||||
));
|
||||
$this->assertEquals($expectedjson, quiz_build_random_question_tag_json($tagrecords));
|
||||
}
|
||||
|
||||
public function test_quiz_extract_random_question_tags() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Setup test data.
|
||||
$footagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'foo',
|
||||
'description' => 'foo desc'
|
||||
);
|
||||
$footag = $this->getDataGenerator()->create_tag($footagrecord);
|
||||
$bartagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'bar',
|
||||
'description' => 'bar desc'
|
||||
);
|
||||
$bartag = $this->getDataGenerator()->create_tag($bartagrecord);
|
||||
$baztagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'baz',
|
||||
'description' => 'baz desc'
|
||||
);
|
||||
$baztag = $this->getDataGenerator()->create_tag($baztagrecord);
|
||||
$quxtagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'qux',
|
||||
'description' => 'qux desc'
|
||||
);
|
||||
$quxtag = $this->getDataGenerator()->create_tag($quxtagrecord);
|
||||
$quuxtagrecord = array(
|
||||
'isstandard' => 1,
|
||||
'flag' => 0,
|
||||
'rawname' => 'quux',
|
||||
'description' => 'quux desc'
|
||||
);
|
||||
$quuxtag = $this->getDataGenerator()->create_tag($quuxtagrecord);
|
||||
|
||||
$tagjson = json_encode(array(
|
||||
[
|
||||
'id' => $footag->id,
|
||||
'name' => 'foo'
|
||||
],
|
||||
[
|
||||
'id' => 999, // An invalid tag id.
|
||||
'name' => 'bar'
|
||||
],
|
||||
[
|
||||
'id' => null,
|
||||
'name' => 'baz'
|
||||
],
|
||||
[
|
||||
'id' => $quxtag->id,
|
||||
'name' => 'invalidqux' // An invalid tag name.
|
||||
],
|
||||
[
|
||||
'id' => 999, // An invalid tag id.
|
||||
'name' => 'invalidquux' // An invalid tag name.
|
||||
],
|
||||
));
|
||||
|
||||
$expectedrecords = array(
|
||||
(object)['id' => $footag->id, 'name' => $footag->name],
|
||||
(object)['id' => $bartag->id, 'name' => $bartag->name],
|
||||
(object)['id' => $baztag->id, 'name' => $baztag->name],
|
||||
(object)['id' => $quxtag->id, 'name' => $quxtag->name],
|
||||
(object)['id' => null, 'name' => 'invalidquux'],
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedrecords, quiz_extract_random_question_tags($tagjson));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates a quiz with some standard (non-random) and some random questions.
|
||||
* The standard questions are created first and then random questions follow them.
|
||||
|
@ -36,6 +36,7 @@ class mod_quiz_tags_testcase extends advanced_testcase {
|
||||
global $CFG, $USER, $DB;
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
@ -82,8 +83,16 @@ class mod_quiz_tags_testcase extends advanced_testcase {
|
||||
$tag3 = core_tag_tag::get_by_name(0, 't3', 'id, name');
|
||||
$this->assertNotFalse($tag3);
|
||||
|
||||
$tagrecords = array($tag2->to_object());
|
||||
$this->assertEquals(quiz_build_random_question_tag_json($tagrecords), $question->randomfromtags);
|
||||
$slottags = quiz_retrieve_slot_tags($question->slotid);
|
||||
$this->assertEquals(
|
||||
[
|
||||
['tagid' => $tag2->id, 'tagname' => $tag2->name]
|
||||
],
|
||||
array_map(function($tag) {
|
||||
return ['tagid' => $tag->tagid, 'tagname' => $tag->tagname];
|
||||
}, $slottags),
|
||||
'', 0.0, 10, true
|
||||
);
|
||||
|
||||
$defaultcategory = question_get_default_category(context_course::instance($newcourseid)->id);
|
||||
$this->assertEquals($defaultcategory->id, $question->randomfromcategory);
|
||||
|
Loading…
x
Reference in New Issue
Block a user