MDL-61614 Quiz: Restore tags for random questions

This commit is contained in:
Shamim Rezaie 2018-04-10 08:47:10 +10:00
parent 2a1855887d
commit 9da6f4d968
5 changed files with 37 additions and 216 deletions

View File

@ -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) {

View File

@ -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.

Binary file not shown.

View File

@ -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.

View File

@ -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);