MDL-61380 Quiz,Questions: Adding "random" question by tag
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user