MDL-61380 Quiz,Questions: Adding "random" question by tag

This commit is contained in:
Shamim Rezaie
2018-03-07 00:30:32 +11:00
parent 4fa49cc647
commit 4f964a1ca0
6 changed files with 96 additions and 25 deletions
+9 -1
View File
@@ -102,7 +102,15 @@ if ($data = $mform->get_data()) {
'It seems a form was submitted without any button being pressed???');
}
quiz_add_random_questions($quiz, $addonpage, $categoryid, $data->numbertoadd, $includesubcategories);
if (empty($data->fromtags)) {
$data->fromtags = [];
}
$tagids = array_map(function($tagstrings) {
return (int)explode(',', $tagstrings)[0];
}, $data->fromtags);
quiz_add_random_questions($quiz, $addonpage, $categoryid, $data->numbertoadd, $includesubcategories, $tagids);
quiz_delete_previews($quiz);
quiz_update_sumgrades($quiz);
redirect($returnurl);
+12
View File
@@ -56,6 +56,18 @@ class quiz_add_random_form extends moodleform {
$tops = question_get_top_categories_for_contexts(array_column($contexts->all(), 'id'));
$mform->hideIf('includesubcategories', 'category', 'in', $tops);
$tags = core_tag_tag::get_tags_by_area_in_contexts('core_question', 'question', $usablecontexts);
$tagstrings = array();
foreach ($tags as $tag) {
$tagstrings["{$tag->id},{$tag->name}"] = $tag->name;
}
$options = array(
'multiple' => true,
'noselectionstring' => get_string('anytags', 'quiz'),
);
$mform->addElement('autocomplete', 'fromtags', get_string('randomquestiontags', 'mod_quiz'), $tagstrings, $options);
$mform->addHelpButton('fromtags', 'randomquestiontags', 'mod_quiz');
$mform->addElement('select', 'numbertoadd', get_string('randomnumber', 'quiz'),
$this->get_number_of_questions_to_add_choices());
+5
View File
@@ -80,6 +80,7 @@ $string['answers'] = 'Answers';
$string['answersingleno'] = 'Multiple answers allowed';
$string['answersingleyes'] = 'One answer only';
$string['answertoolong'] = 'Answer too long after line {$a} (255 char. max)';
$string['anytags'] = 'Any tags';
$string['aon'] = 'AON format';
$string['areyousureremoveselected'] = 'Are you sure you want to remove all the selected questions?';
$string['asshownoneditscreen'] = 'As shown on the edit screen';
@@ -699,6 +700,10 @@ $string['randomfromcategory'] = 'Random question from category:';
$string['randomfromexistingcategory'] = 'Random question from an existing category';
$string['randomnumber'] = 'Number of random questions';
$string['randomnosubcat'] = 'Questions from this category only, not its subcategories.';
$string['randomquestiontags'] = 'Tags';
$string['randomquestiontags_help'] = 'You can restrict the selection criteria further by specifying some question tags here.
The "random" questions will be selected from the questions that have all these tags.';
$string['randomquestionusinganewcategory'] = 'Random question using a new category';
$string['randomwithsubcat'] = 'Questions from this category and its subcategories.';
$string['readytosend'] = 'You are about to send your whole quiz to be graded. Are you sure you want to continue?';
+17 -3
View File
@@ -2173,9 +2173,10 @@ function quiz_update_section_firstslots($quizid, $direction, $afterslot, $before
* @param int $categoryid the question category to add the question from.
* @param int $number the number of random questions to add.
* @param bool $includesubcategories whether to include questoins from subcategories.
* @param int[] $tagids Array of tagids. The question that will be picked randomly should be tagged with all these tags.
*/
function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
$includesubcategories) {
$includesubcategories, $tagids = []) {
global $DB;
$category = $DB->get_record('question_categories', array('id' => $categoryid));
@@ -2187,6 +2188,18 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
require_capability('moodle/question:useall', $catcontext);
$tags = [];
$tagstrings = [];
foreach ($tagids as $tagid) {
if ($tag = core_tag_tag::get($tagid, 'id,name')) {
$tags[] = [
'id' => $tagid,
'name' => $tag->name
];
$tagstrings[] = "{$tagid},{$tag->name}";
} else if (!empty($tagid)) {
print_error('invalidtagid', 'mod_quiz');
}
}
// Find existing random questions in this category that are
// not used by any quiz.
@@ -2199,14 +2212,15 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
SELECT *
FROM {quiz_slots}
WHERE questionid = q.id)
ORDER BY id", array($category->id, ($includesubcategories ? '1' : '0')));
ORDER BY id", array($category->id, $includesubcategories ? '1' : '0'));
for ($i = 0; $i < $number; $i++) {
// Take as many of orphaned "random" questions as needed.
if (!$question = array_shift($existingquestions)) {
$form = new stdClass();
$form->questiontext = array('text' => ($includesubcategories ? '1' : '0'), 'format' => 0);
$form->category = $category->id . ',' . $category->contextid;
$form->includesubcategories = $includesubcategories;
$form->fromtags = $tagstrings;
$form->defaultmark = 1;
$form->hidden = 1;
$form->stamp = make_unique_id_code(); // Set the unique code (not to be changed).
@@ -30,10 +30,17 @@ $string['pluginname_help'] = 'A random question is not a question type as such,
$string['pluginnameediting'] = 'Editing a random question';
$string['randomqname'] = 'Random ({$a})';
$string['randomqnamefromtop'] = 'Faulty random question! Please delete this question.';
$string['randomqnamefromtoptags'] = 'Faulty random question! Please delete this question.';
$string['randomqnametags'] = 'Random ({$a->category}, tags: {$a->tags})';
$string['randomqplusname'] = 'Random ({$a} and subcategories)';
$string['randomqplusnamecourse'] = 'Random (Any category in this course)';
$string['randomqplusnamecoursecat'] = 'Random (Any category inside course category {$a})';
$string['randomqplusnamecoursecattags'] = 'Random (Any category inside course category {$a->category}, tags: {$a->tags})';
$string['randomqplusnamecoursetags'] = 'Random (Any category in this course, tags: {$a->tags})';
$string['randomqplusnamemodule'] = 'Random (Any category of this quiz)';
$string['randomqplusnamemoduletags'] = 'Random (Any category of this quiz, tags: {$a->tags})';
$string['randomqplusnamesystem'] = 'Random (Any system-level category)';
$string['randomqplusnamesystemtags'] = 'Random (Any system-level category, tags: {$a->tags})';
$string['randomqplusnametags'] = 'Random ({$a->category} and subcategories, tags: {$a->tags})';
$string['selectedby'] = '{$a->questionname} selected by {$a->randomname}';
$string['selectmanualquestions'] = 'Random questions can use manually graded questions';
+46 -21
View File
@@ -122,41 +122,59 @@ class qtype_random extends question_type {
/**
* Random questions always get a question name that is Random (cateogryname).
* This function is a centralised place to calculate that, given the category.
* @param object $category the category this question picks from. (Only ->name is used.)
* @param stdClass $category the category this question picks from. (Only ->name is used.)
* @param bool $includesubcategories whether this question also picks from subcategories.
* @param string[] $tagnames Name of tags this question picks from.
* @return string the name this question should have.
*/
public function question_name($category, $includesubcategories) {
public function question_name($category, $includesubcategories, $tagnames = []) {
$categoryname = '';
if ($category->parent && $includesubcategories) {
$name = get_string('randomqplusname', 'qtype_random', shorten_text($category->name, 100));
$stringid = 'randomqplusname';
$categoryname = shorten_text($category->name, 100);
} else if ($category->parent) {
$name = get_string('randomqname', 'qtype_random', shorten_text($category->name, 100));
$stringid = 'randomqname';
$categoryname = shorten_text($category->name, 100);
} else if ($includesubcategories) {
$context = context::instance_by_id($category->contextid);
switch ($context->contextlevel) {
case CONTEXT_MODULE:
$name = get_string('randomqplusnamemodule', 'qtype_random');
$stringid = 'randomqplusnamemodule';
break;
case CONTEXT_COURSE:
$name = get_string('randomqplusnamecourse', 'qtype_random');
$stringid = 'randomqplusnamecourse';
break;
case CONTEXT_COURSECAT:
$name = get_string('randomqplusnamecoursecat', 'qtype_random',
shorten_text($context->get_context_name(false), 100));
$stringid = 'randomqplusnamecoursecat';
$categoryname = shorten_text($context->get_context_name(false), 100);
break;
case CONTEXT_SYSTEM:
$name = get_string('randomqplusnamesystem', 'qtype_random');
$stringid = 'randomqplusnamesystem';
break;
default: // Impossible.
$name = '';
}
} else {
// No question will ever be selected. So, let's warn the teacher.
$name = get_string('randomqnamefromtop', 'qtype_random');
$stringid = 'randomqnamefromtop';
}
return $name;
if ($tagnames) {
$stringid .= 'tags';
$a = new stdClass();
if ($categoryname) {
$a->category = $categoryname;
}
$a->tags = implode(',', array_map(function($tagname) {
return explode(',', $tagname)[1];
}, $tagnames));
} else {
$a = $categoryname ? : null;
}
$name = get_string($stringid, 'qtype_random', $a);
return shorten_text($name, 255);
}
protected function set_selected_question_name($question, $randomname) {
@@ -172,17 +190,24 @@ class qtype_random extends question_type {
$form->name = '';
list($category) = explode(',', $form->category);
// In case someone set the question text to true/false in the old style, set it properly.
if ($form->questiontext['text']) {
$form->questiontext['text'] = '1';
} else if ($DB->record_exists('question_categories', ['id' => $category, 'parent' => 0])) {
// The chosen category is a top category.
$form->questiontext['text'] = '1';
} else {
$form->questiontext['text'] = '0';
if (!$form->includesubcategories) {
if ($DB->record_exists('question_categories', ['id' => $category, 'parent' => 0])) {
// The chosen category is a top category.
$form->includesubcategories = true;
}
}
$form->tags = array();
if (empty($form->fromtags)) {
$form->fromtags = array();
}
$form->questiontext = array(
'text' => $form->includesubcategories ? '1' : '0',
'format' => 0
);
// Name is not a required field for random questions, but
// parent::save_question Assumes that it is.
return parent::save_question($question, $form);
@@ -201,7 +226,7 @@ class qtype_random extends question_type {
// We also force the question name to be 'Random (categoryname)'.
$category = $DB->get_record('question_categories',
array('id' => $question->category), '*', MUST_EXIST);
$updateobject->name = $this->question_name($category, !empty($question->questiontext));
$updateobject->name = $this->question_name($category, $question->includesubcategories, $question->fromtags);
return $DB->update_record('question', $updateobject);
}