MDL-73602 quiz: Remove all qtype_random references
This removes the use of the "random" qtype for random questions from the quiz module. Instead, the quiz structure now idenfies slots containing random questions using a `random` boolean field on the slot. This includes some amendments to statistics classes in the core_question namespace, as they ultimately get their question data from mod/quiz/report/reportlib.php It also introduces a proper (if limited) way to add random questions in behat tests.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
namespace mod_quiz\output;
|
||||
|
||||
use core_question\local\bank\question_version_status;
|
||||
use mod_quiz\question\bank\qbank_helper;
|
||||
use \mod_quiz\structure;
|
||||
use \html_writer;
|
||||
use qbank_previewquestion\question_preview_options;
|
||||
@@ -802,7 +803,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
];
|
||||
|
||||
$data['versionoptions'] = [];
|
||||
if ($structure->get_slot_by_number($slot)->qtype !== 'random') {
|
||||
if (!$structure->get_slot_by_number($slot)->random) {
|
||||
$data['versionselection'] = true;
|
||||
$data['versionoption'] = $structure->get_version_choices_for_slot($slot);
|
||||
}
|
||||
@@ -846,7 +847,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
*/
|
||||
public function get_question_name_for_slot(structure $structure, int $slot, \moodle_url $pageurl): string {
|
||||
// Display the link to the question (or do nothing if question has no url).
|
||||
if ($structure->get_question_type_for_slot($slot) === 'random') {
|
||||
if ($structure->get_slot_by_number($slot)->random) {
|
||||
$questionname = $this->random_question($structure, $slot, $pageurl);
|
||||
} else {
|
||||
$questionname = $this->question_name($structure, $slot, $pageurl);
|
||||
@@ -868,7 +869,7 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
$qtype = $structure->get_question_type_for_slot($slot);
|
||||
$slotinfo = $structure->get_slot_by_number($slot);
|
||||
$questionicons = '';
|
||||
if ($qtype !== 'random' && question_bank::is_qtype_usable($qtype)) {
|
||||
if (!$slotinfo->random && question_bank::is_qtype_usable($qtype)) {
|
||||
$questionicons .= $this->question_preview_icon($structure->get_quiz(),
|
||||
$structure->get_question_in_slot($slot),
|
||||
null, null, $slotinfo->requestedversion ?: question_preview_options::ALWAYS_LATEST);
|
||||
@@ -1128,9 +1129,8 @@ class edit_renderer extends \plugin_renderer_base {
|
||||
}
|
||||
|
||||
$configuretitle = get_string('configurerandomquestion', 'quiz');
|
||||
$qtype = question_bank::get_qtype($question->qtype, false);
|
||||
$namestr = $qtype->local_name();
|
||||
$icon = $this->pix_icon('icon', $namestr, $qtype->plugin_name(), ['class' => 'icon activityicon']);
|
||||
$namestr = get_string('randomquestion', 'quiz');
|
||||
$icon = $this->pix_icon('random', $namestr, 'mod_quiz', ['class' => 'icon activityicon']);
|
||||
|
||||
$editicon = $this->pix_icon('t/edit', $configuretitle, 'moodle', ['title' => '']);
|
||||
$qbankurlparams = [
|
||||
|
||||
@@ -166,6 +166,7 @@ class qbank_helper {
|
||||
foreach ($slotdata as $slot) {
|
||||
// Ensure the right id is the id.
|
||||
$slot->id = $slot->slotid;
|
||||
$slot->random = false;
|
||||
|
||||
if ($slot->filtercondition) {
|
||||
// Unpack the information about a random question.
|
||||
@@ -175,7 +176,8 @@ class qbank_helper {
|
||||
|
||||
$slot->category = $slot->filtercondition['filter']['category']['values'][0] ?? 0;
|
||||
|
||||
$slot->qtype = 'random';
|
||||
$slot->qtype = null; // Random slots don’t have an associated question.
|
||||
$slot->random = true;
|
||||
$slot->name = get_string('random', 'quiz');
|
||||
$slot->length = 1;
|
||||
} else if ($slot->qtype === null) {
|
||||
@@ -254,7 +256,7 @@ class qbank_helper {
|
||||
$slotdata = reset($slotdata);
|
||||
|
||||
// Non-random question.
|
||||
if ($slotdata->qtype != 'random') {
|
||||
if (!$slotdata->random) {
|
||||
return $slotdata->questionid;
|
||||
}
|
||||
|
||||
|
||||
@@ -594,7 +594,7 @@ class quiz_settings {
|
||||
// Skip questions where all versions are draft.
|
||||
continue;
|
||||
}
|
||||
if ($questiondata->qtype === 'random' && $includepotential) {
|
||||
if ($questiondata->random && $includepotential) {
|
||||
$filtercondition = $questiondata->filtercondition;
|
||||
if (!empty($filtercondition)) {
|
||||
$filter = $filtercondition['filter'];
|
||||
|
||||
@@ -272,7 +272,7 @@ class structure {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_array($this->get_question_type_for_slot($slotnumber), ['random', 'missingtype'])) {
|
||||
if ($this->slotsinorder[$slotnumber]->random || $this->get_question_type_for_slot($slotnumber) === 'missingtype') {
|
||||
return \question_engine::can_questions_finish_during_the_attempt(
|
||||
$this->quizobj->get_quiz()->preferredbehaviour);
|
||||
}
|
||||
@@ -1796,7 +1796,7 @@ class structure {
|
||||
// Find the random slots.
|
||||
$allslots = $this->get_slots();
|
||||
foreach ($allslots as $key => $slot) {
|
||||
if ($slot->qtype != 'random') {
|
||||
if (!$slot->random) {
|
||||
unset($allslots[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $time
|
||||
if ($questiondata->status == \core_question\local\bank\question_version_status::QUESTION_STATUS_DRAFT) {
|
||||
throw new moodle_exception('questiondraftonly', 'mod_quiz', '', $questiondata->name);
|
||||
}
|
||||
if ($questiondata->qtype == 'random') {
|
||||
if ($questiondata->random) {
|
||||
$randomfound = true;
|
||||
continue;
|
||||
}
|
||||
@@ -204,7 +204,7 @@ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $time
|
||||
|
||||
foreach ($quizobj->get_questions(null, false) as $questiondata) {
|
||||
$slot += 1;
|
||||
if ($questiondata->qtype != 'random') {
|
||||
if (!$questiondata->random) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1039,7 +1039,7 @@ function quiz_attempt_state_name($state) {
|
||||
*/
|
||||
function quiz_question_action_icons($quiz, $cmid, $question, $returnurl, $variant = null) {
|
||||
$html = '';
|
||||
if ($question->qtype !== 'random') {
|
||||
if (!$question->random) {
|
||||
$html = quiz_question_preview_button($quiz, $question, false, $variant);
|
||||
}
|
||||
$html .= quiz_question_edit_button($cmid, $question, $returnurl);
|
||||
@@ -1748,15 +1748,7 @@ function quiz_add_quiz_question($questionid, $quiz, $page = 0, $maxmark = null)
|
||||
$quiz->cmid = $cm->id;
|
||||
}
|
||||
|
||||
// Make sue the question is not of the "random" type.
|
||||
$questiontype = $DB->get_field('question', 'qtype', ['id' => $questionid]);
|
||||
if ($questiontype == 'random') {
|
||||
throw new coding_exception(
|
||||
'Adding "random" questions via quiz_add_quiz_question() is deprecated. '.
|
||||
'Please use mod_quiz\structure::add_random_questions().'
|
||||
);
|
||||
}
|
||||
|
||||
// If the question type is invalid, we cannot add it to the quiz. It shouldn't be possible to get to this
|
||||
// point without fiddling with the DOM so we can just throw an exception.
|
||||
if (!\question_bank::is_qtype_installed($questiontype)) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="isolation:isolate" width="16" height="16" preserveAspectRatio="xMinYMid meet"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)"><path d="M14.7 5.5l-.096 5.97-5.008 3.23L9.5 8.143 14.7 5.5zM7.8 1.1l5.7 2.3-4.9 3-5.8-2.8 5-2.5zm-.1 7l.1 6.7-5.9-3.2-.1-6.7 5.9 3.2z" vector-effect="non-scaling-stroke" stroke="#000" stroke-miterlimit="10"/><path d="M7.9.1s-.1 0-.1.1L1.6 3.6c-.1 0 0 0 0 .1l6.9 3.5c.1.1.2.1.3 0l6.1-3.7c.1-.1.1-.1 0-.2L8.2.3C8.1.1 8 .1 7.9.1zm-.6.8h.4c.6 0 1.1.3 1.1.6 0 .2-.5.5-1.1.5-.6 0-1.1-.3-1.1-.6 0-.2.3-.4.7-.5zM3.8 2.8h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6s.3-.5.7-.6zm5.7-.9h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6-.1-1-.3-1-.7 0-.2.3-.4.6-.5zM1.2 4c0 .1 0 .1 0 0l.1 7.9c0 .1 0 .1.1.1l6.7 3.7c.2.1.2.1.2-.1v-8c0-.1 0-.2-.1-.2L1.2 4c.1.1 0 0 0 0zM6 3.9h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.5c-.6 0-1.1-.2-1-.5 0-.3.2-.5.6-.6zm5.8-1h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6.1-.3.3-.5.7-.6zM1.9 5.4c0-.1 0-.1 0 0 .3-.1.7.1 1 .5.3.5.3 1.1.1 1.4-.3.2-.8.1-1.2-.4-.3-.5-.4-1.2-.1-1.4.1-.1.1-.1.2-.1zM8.3 5h.4c.6 0 1.1.3 1.1.6s-.5.6-1.1.6c-.6 0-1.1-.3-1.1-.6.1-.3.3-.5.7-.6zm7-1.3s0 .1 0 0L9 7.6c-.1.1-.1.1-.1.2v7.9c0 .1 0 .2.1.1l6.2-3.9c.1-.1.1-.1.1-.2v-8c.1 0 .1 0 0 0zm-.8 1.5c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.4.6-.4zM6.4 7.6c.3 0 .6.2.9.5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.4-.5-.4-1.1-.1-1.4 0 0 .1 0 .2-.1zM4.1 9c.3 0 .7.2.9.5.3.5.4 1.1.1 1.4-.2.3-.7.1-1.1-.4-.3-.5-.4-1.1-.1-1.4.1 0 .1-.1.2-.1zm-2.2 1.4c.1 0 .1 0 0 0 .3-.1.7.1 1 .5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.3-.5-.4-1.1-.1-1.4 0-.1.1-.1.1-.1zm10.7-1.5c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.3.6-.4zm-6.3 3.9c.1-.1.1-.1 0 0 .3-.1.7.1 1 .5.3.5.4 1.1.1 1.4-.3.3-.8.1-1.1-.4-.3-.5-.4-1.1-.1-1.4 0-.1.1-.1.1-.1zm4.2-.1c.2 0 .4 0 .5.2.2.3.1 1-.3 1.4-.4.4-.9.5-1.1.2-.2-.3-.1-1 .3-1.4.2-.2.4-.4.6-.4z" fill="#C4CCCB"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -111,6 +111,7 @@ function quiz_report_get_significant_questions($quiz) {
|
||||
$slotreport->slot = $slot->slot;
|
||||
$slotreport->id = $slot->questionid;
|
||||
$slotreport->qtype = $slot->qtype;
|
||||
$slotreport->random = $slot->random;
|
||||
$slotreport->length = $slot->length;
|
||||
$slotreport->number = $number;
|
||||
$slotreport->displaynumber = $slot->displaynumber ?? $number;
|
||||
|
||||
@@ -54,7 +54,6 @@ final class responses_from_steps_walkthrough_test extends \mod_quiz\tests\attemp
|
||||
*/
|
||||
public function test_walkthrough_from_csv($quizsettings, $csvdata): void {
|
||||
$this->resetAfterTest(true);
|
||||
question_bank::get_qtype('random')->clear_caches_before_testing();
|
||||
|
||||
$this->create_quiz($quizsettings, $csvdata['questions']);
|
||||
|
||||
|
||||
@@ -891,7 +891,7 @@ class quiz_statistics_report extends report_base {
|
||||
$questiondata = [];
|
||||
foreach ($questions as $qs => $question) {
|
||||
$displaynumber = $question->displaynumber;
|
||||
if ($question->qtype === 'random') {
|
||||
if ($question->random) {
|
||||
$question->id = 0;
|
||||
$question->name = get_string('random', 'quiz');
|
||||
$question->questiontext = get_string('random', 'quiz');
|
||||
@@ -909,6 +909,7 @@ class quiz_statistics_report extends report_base {
|
||||
$q->slot = $question->slot;
|
||||
$q->number = $displaynumber;
|
||||
$q->parenttype = null;
|
||||
$q->random = false;
|
||||
$questiondata[$question->slot] = $q;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
$number = $number . '.'.$questionstat->subqdisplayorder;
|
||||
}
|
||||
|
||||
if ($questionstat->question->qtype != 'random' && !is_null($questionstat->variant)) {
|
||||
if (!$questionstat->question->random && !is_null($questionstat->variant)) {
|
||||
$number = $number . '.'.$questionstat->variant;
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ class quiz_statistics_table extends flexible_table {
|
||||
// Question in a slot, we are not on a page showing structural analysis of one slot,
|
||||
// we don't want linking on those pages.
|
||||
$number = $questionstat->question->number;
|
||||
$israndomquestion = $questionstat->question->qtype == 'random';
|
||||
$israndomquestion = $questionstat->question->random;
|
||||
$url = new moodle_url($baseurl, ['slot' => $questionstat->slot]);
|
||||
|
||||
if ($this->is_calculated_question_summary($questionstat)) {
|
||||
|
||||
@@ -25,13 +25,12 @@ Feature: Statistics calculations with random questions
|
||||
| questioncategory | qtype | template | name | questiontext |
|
||||
| Test questions | essay | plain | Test question 1 | |
|
||||
| Test questions | essay | plain | Test question 2 | |
|
||||
| Test questions | random | | Random (Test questions) | 0 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| quiz | Quiz 1 | C1 | quiz1 |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page |
|
||||
| Random (Test questions) | 1 |
|
||||
| question | page | randomcategory |
|
||||
| Random (Test questions) | 1 | Test questions |
|
||||
And user "student" has attempted "Quiz 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | Here is my wonderful essay |
|
||||
@@ -43,13 +42,12 @@ Feature: Statistics calculations with random questions
|
||||
| questioncategory | qtype | template | name | questiontext |
|
||||
| Test questions | multichoice | one_of_four | Test question 1 | |
|
||||
| Test questions | multichoice | one_of_four | Test question 2 | |
|
||||
| Test questions | random | | Random (Test questions) | 0 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| quiz | Quiz 1 | C1 | quiz1 |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page |
|
||||
| Random (Test questions) | 1 |
|
||||
| question | page | randomcategory |
|
||||
| Random (Test questions) | 1 | Test questions |
|
||||
And user "student" has attempted "Quiz 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | One |
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
slot,id,number,category,parent,name,questiontext,questiontextformat,image,generalfeedback,defaultgrade,penalty,qtype,length,stamp,version,hidden,timecreated,timemodified,createdby,modifiedby,maxmark
|
||||
1,1,1,5,0,questionessay-11,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+WeUaUK,localhost+080922073527+qxLjv1,0,1222068927,0,2,NULL,1
|
||||
2,2,2,5,0,questionessay-17,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+pvCseX,localhost+080922073527+mzy6tY,0,1222068927,0,2,NULL,1
|
||||
3,3,3,5,0,questionessay-6,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+Cr3gDO,localhost+080922073527+hnxfTy,0,1222068927,0,2,NULL,1
|
||||
4,4,4,5,0,questionessay-8,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+sSq9ln,localhost+080922073527+PGyab3,0,1222068927,0,2,NULL,1
|
||||
5,5,5,5,0,questionmatch-10,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+oG1i2f,localhost+080922073527+S1UxZy,0,1222068927,0,2,NULL,0
|
||||
6,6,6,5,0,questionmatch-16,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+vMFHyY,localhost+080922073527+4GZIyQ,0,1222068927,0,2,NULL,0
|
||||
7,7,7,5,0,questionmatch-18,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+Xkxqn1,localhost+080922073527+xbU6U7,0,1222068927,0,2,NULL,0
|
||||
8,8,8,5,0,questionmultianswer-12,This question consists of some text with an answer embedded right here {#1} and right after that you will have to deal with this short answer {#2} and finally we have a floating point number {#3}. Note that addresses like www.moodle.org and smileys :-) all work as normal: a) How good is this? {#4} b) What grade would you give it? {#5} Good luck!,0,,General feedback,8,0.1,multianswer,1,localhost+080922073527+0zKgpF,localhost+080922073527+r1gsde,0,1222068927,0,2,NULL,8
|
||||
9,14,9,5,0,questionmultichoice-13,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+AjIjeV,localhost+080922073527+UhtTLR,0,1222068927,0,2,NULL,1
|
||||
10,15,10,5,0,questionmultichoice-14,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+IrAqRl,localhost+080922073527+xRfta8,0,1222068927,0,2,NULL,1
|
||||
11,16,11,5,0,questionmultichoice-3,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+DMGirU,localhost+080922073527+689V8k,0,1222068927,0,2,NULL,1
|
||||
12,17,12,5,0,questionmultichoice-5,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+wileZw,localhost+080922073527+zGcaDa,0,1222068927,0,2,NULL,1
|
||||
13,25,13,5,0,Random Short-Answer Matching,"<p>For each of the following questions, select the matching answer from the menu.</p>",1,,,1,0.1,randomsamatch,1,localhost+080922073724+qF803I,localhost+080922075820+zbZtaD,0,1222069044,1222070300,2,2,1
|
||||
14,22,14,5,0,Is Thai difficult?,Is Thai difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+2FLtCU,localhost+080922073655+fgUeOj,0,1222069015,0,2,NULL,1
|
||||
15,23,15,5,0,Is Thai grammar difficult?,Is Thai grammar difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+LYSD32,localhost+080922073655+WgRYk4,0,1222069015,0,2,NULL,1
|
||||
16,24,16,5,0,Is Thai pronunciation difficult?,Is Thai pronunciation difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+5p1w22,localhost+080922073655+g5jrXa,0,1222069015,0,2,NULL,1
|
||||
17,20,17,5,0,Who's buried in Grant's tomb?,Who's buried in Grant's tomb?,0,,,1,0.1,shortanswer,1,localhost+080922073655+PTDcDZ,localhost+080922073655+aghyfu,0,1222069015,0,2,NULL,1
|
||||
18,21,18,5,0,Who's buried in Jamie's tomb?,Who's buried in Jamie's tomb?,0,,,1,0.1,shortanswer,1,localhost+080922073655+Xvy1ns,localhost+080922073655+Mx0Izs,0,1222069015,0,2,NULL,1
|
||||
19,18,19,5,0,questiontruefalse-7,This question is really stupid,0,,Well done,1,1,truefalse,1,localhost+080922073527+9bzTef,localhost+080922073527+hjcQR1,0,1222068927,0,2,NULL,1
|
||||
20,19,20,5,0,questiontruefalse-9,This question is really stupid,0,,Well done,1,1,truefalse,1,localhost+080922073527+TI0yD4,localhost+080922073527+iXIulQ,0,1222068927,0,2,NULL,1
|
||||
slot,id,number,category,parent,name,questiontext,questiontextformat,image,generalfeedback,defaultgrade,penalty,qtype,length,stamp,version,hidden,timecreated,timemodified,createdby,modifiedby,maxmark,random
|
||||
1,1,1,5,0,questionessay-11,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+WeUaUK,localhost+080922073527+qxLjv1,0,1222068927,0,2,NULL,1,0
|
||||
2,2,2,5,0,questionessay-17,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+pvCseX,localhost+080922073527+mzy6tY,0,1222068927,0,2,NULL,1,0
|
||||
3,3,3,5,0,questionessay-6,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+Cr3gDO,localhost+080922073527+hnxfTy,0,1222068927,0,2,NULL,1,0
|
||||
4,4,4,5,0,questionessay-8,What is the purpose of life?,0,,General feedback,1,0,essay,1,localhost+080922073527+sSq9ln,localhost+080922073527+PGyab3,0,1222068927,0,2,NULL,1,0
|
||||
5,5,5,5,0,questionmatch-10,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+oG1i2f,localhost+080922073527+S1UxZy,0,1222068927,0,2,NULL,0,0
|
||||
6,6,6,5,0,questionmatch-16,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+vMFHyY,localhost+080922073527+4GZIyQ,0,1222068927,0,2,NULL,0,0
|
||||
7,7,7,5,0,questionmatch-18,"test question, generated by script",0,,Well done,1,0.1,match,1,localhost+080922073527+Xkxqn1,localhost+080922073527+xbU6U7,0,1222068927,0,2,NULL,0,0
|
||||
8,8,8,5,0,questionmultianswer-12,This question consists of some text with an answer embedded right here {#1} and right after that you will have to deal with this short answer {#2} and finally we have a floating point number {#3}. Note that addresses like www.moodle.org and smileys :-) all work as normal: a) How good is this? {#4} b) What grade would you give it? {#5} Good luck!,0,,General feedback,8,0.1,multianswer,1,localhost+080922073527+0zKgpF,localhost+080922073527+r1gsde,0,1222068927,0,2,NULL,8,0
|
||||
9,14,9,5,0,questionmultichoice-13,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+AjIjeV,localhost+080922073527+UhtTLR,0,1222068927,0,2,NULL,1,0
|
||||
10,15,10,5,0,questionmultichoice-14,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+IrAqRl,localhost+080922073527+xRfta8,0,1222068927,0,2,NULL,1,0
|
||||
11,16,11,5,0,questionmultichoice-3,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+DMGirU,localhost+080922073527+689V8k,0,1222068927,0,2,NULL,1,0
|
||||
12,17,12,5,0,questionmultichoice-5,How old is the sun?,0,,General feedback,1,0.1,multichoice,1,localhost+080922073527+wileZw,localhost+080922073527+zGcaDa,0,1222068927,0,2,NULL,1,0
|
||||
13,25,13,5,0,Random Short-Answer Matching,"<p>For each of the following questions, select the matching answer from the menu.</p>",1,,,1,0.1,randomsamatch,1,localhost+080922073724+qF803I,localhost+080922075820+zbZtaD,0,1222069044,1222070300,2,2,1,0
|
||||
14,22,14,5,0,Is Thai difficult?,Is Thai difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+2FLtCU,localhost+080922073655+fgUeOj,0,1222069015,0,2,NULL,1,0
|
||||
15,23,15,5,0,Is Thai grammar difficult?,Is Thai grammar difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+LYSD32,localhost+080922073655+WgRYk4,0,1222069015,0,2,NULL,1,0
|
||||
16,24,16,5,0,Is Thai pronunciation difficult?,Is Thai pronunciation difficult?,0,,,1,0.1,shortanswer,1,localhost+080922073655+5p1w22,localhost+080922073655+g5jrXa,0,1222069015,0,2,NULL,1,0
|
||||
17,20,17,5,0,Who's buried in Grant's tomb?,Who's buried in Grant's tomb?,0,,,1,0.1,shortanswer,1,localhost+080922073655+PTDcDZ,localhost+080922073655+aghyfu,0,1222069015,0,2,NULL,1,0
|
||||
18,21,18,5,0,Who's buried in Jamie's tomb?,Who's buried in Jamie's tomb?,0,,,1,0.1,shortanswer,1,localhost+080922073655+Xvy1ns,localhost+080922073655+Mx0Izs,0,1222069015,0,2,NULL,1,0
|
||||
19,18,19,5,0,questiontruefalse-7,This question is really stupid,0,,Well done,1,1,truefalse,1,localhost+080922073527+9bzTef,localhost+080922073527+hjcQR1,0,1222068927,0,2,NULL,1,0
|
||||
20,19,20,5,0,questiontruefalse-9,This question is really stupid,0,,Well done,1,1,truefalse,1,localhost+080922073527+TI0yD4,localhost+080922073527+iXIulQ,0,1222068927,0,2,NULL,1,0
|
||||
|
||||
|
@@ -534,7 +534,6 @@ final class attempt_walkthrough_test extends \advanced_testcase {
|
||||
global $SITE;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
question_bank::get_qtype('random')->clear_caches_before_testing();
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
|
||||
@@ -247,9 +247,6 @@ final class repeated_restore_test extends advanced_testcase {
|
||||
global $CFG;
|
||||
$generators = [];
|
||||
foreach (\core\plugin_manager::instance()->get_plugins_of_type('qtype') as $qtype) {
|
||||
if ($qtype->name == 'random') {
|
||||
continue;
|
||||
}
|
||||
$helperpath = "{$CFG->dirroot}/question/type/{$qtype->name}/tests/helper.php";
|
||||
if (!file_exists($helperpath)) {
|
||||
continue;
|
||||
|
||||
@@ -191,14 +191,16 @@ class behat_mod_quiz extends behat_question_base {
|
||||
* Put the specified questions on the specified pages of a given quiz.
|
||||
*
|
||||
* The first row should be column names:
|
||||
* | question | page | maxmark | requireprevious |
|
||||
* | question | page | maxmark | requireprevious | randomcategory | includesubcategories |
|
||||
* The first two of those are required. The others are optional.
|
||||
*
|
||||
* question needs to uniquely match a question name.
|
||||
* question needs to uniquely match a question name, otherwise you must include randomcategory.
|
||||
* page is a page number. Must start at 1, and on each following
|
||||
* row should be the same as the previous, or one more.
|
||||
* maxmark What the question is marked out of. Defaults to question.defaultmark.
|
||||
* requireprevious The question can only be attempted after the previous one was completed.
|
||||
* randomcategory To add a random question, pass a non-existant name for "question", then a valid category name here.
|
||||
* includesubcategories Option for the random question category filter, if randomcategory is specified.
|
||||
*
|
||||
* Then there should be a number of rows of data, one for each question you want to add.
|
||||
*
|
||||
@@ -251,7 +253,7 @@ class behat_mod_quiz extends behat_question_base {
|
||||
JOIN {question_versions} qv ON qv.questionid = q.id
|
||||
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
|
||||
WHERE q.name = :name';
|
||||
$question = $DB->get_record_sql($sql, ['name' => $questiondata['question']], MUST_EXIST);
|
||||
$question = $DB->get_record_sql($sql, ['name' => $questiondata['question']]);
|
||||
|
||||
// Page number.
|
||||
$page = clean_param($questiondata['page'], PARAM_INT);
|
||||
@@ -280,7 +282,14 @@ class behat_mod_quiz extends behat_question_base {
|
||||
}
|
||||
}
|
||||
|
||||
if ($question->qtype == 'random') {
|
||||
if (!$question) {
|
||||
if (!array_key_exists('randomcategory', $questiondata) && $questiondata['randomcategory'] !== '') {
|
||||
throw new ExpectationException(
|
||||
'To add a random question, you must include a category name in the randomcategory column.',
|
||||
$this->getSession()->getDriver(),
|
||||
);
|
||||
}
|
||||
$categoryid = $DB->get_field('question_categories', 'id', ['name' => $questiondata['randomcategory']], MUST_EXIST);
|
||||
if (!array_key_exists('includingsubcategories', $questiondata) || $questiondata['includingsubcategories'] === '') {
|
||||
$includingsubcategories = false;
|
||||
} else {
|
||||
@@ -290,7 +299,7 @@ class behat_mod_quiz extends behat_question_base {
|
||||
$filter = [
|
||||
'category' => [
|
||||
'jointype' => \qbank_managecategories\category_condition::JOINTYPE_DEFAULT,
|
||||
'values' => [$question->category],
|
||||
'values' => [$categoryid],
|
||||
'filteroptions' => ['includesubcategories' => $includingsubcategories],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -61,11 +61,10 @@ Feature: Edit quizzes where some questions require the previous one to have been
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
| Test questions | random | Random (Test questions) | 0 |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page | requireprevious |
|
||||
| Random (Test questions) | 1 | 0 |
|
||||
| TF1 | 1 | 1 |
|
||||
| question | page | requireprevious | randomcategory |
|
||||
| Random (Test questions) | 1 | 0 | Test questions |
|
||||
| TF1 | 1 | 1 | |
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page
|
||||
Then "This question cannot be attempted until the previous question has been completed." "link" should be visible
|
||||
|
||||
@@ -118,12 +117,11 @@ Feature: Edit quizzes where some questions require the previous one to have been
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
| Test questions | truefalse | TF2 | Second question |
|
||||
| Test questions | random | Random (Test questions) | 0 |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page | requireprevious |
|
||||
| Random (Test questions) | 1 | 0 |
|
||||
| TF1 | 1 | 1 |
|
||||
| TF2 | 1 | 1 |
|
||||
| question | page | requireprevious | randomcategory |
|
||||
| Random (Test questions) | 1 | 0 | Test questions |
|
||||
| TF1 | 1 | 1 | |
|
||||
| TF2 | 1 | 1 | |
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page
|
||||
Then "be attempted" "link" in the "TF1" "list_item" should not be visible
|
||||
Then "be attempted" "link" in the "TF2" "list_item" should not be visible
|
||||
|
||||
@@ -31,15 +31,14 @@ Feature: Teacher can build quiz in a single activity format course
|
||||
| Test questions | multichoice | one_of_four | MCQ2 |
|
||||
| Qbank questions 1 | truefalse | | TFQ1 |
|
||||
| Qbank questions 2 | truefalse | | TFQ2 |
|
||||
| Test questions | random | | Random (Test questions) |
|
||||
# Add questions from different question categories and question banks to the quiz.
|
||||
# Add at least 1 random question.
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page |
|
||||
| MCQ1 | 1 |
|
||||
| TFQ1 | 1 |
|
||||
| TFQ2 | 2 |
|
||||
| Random (Test questions) | 3 |
|
||||
| question | page | randomcategory |
|
||||
| MCQ1 | 1 | |
|
||||
| TFQ1 | 1 | |
|
||||
| TFQ2 | 2 | |
|
||||
| Random (Test questions) | 3 | Test questions |
|
||||
|
||||
@javascript
|
||||
Scenario: Student can preview and answer quiz in a single activity format course
|
||||
|
||||
@@ -116,15 +116,11 @@ final class lib_test extends \advanced_testcase {
|
||||
quiz_add_quiz_question($standardq->id, $quiz);
|
||||
$this->add_random_questions($quiz->id, 0, $cat->id, 1);
|
||||
|
||||
// Get the random question.
|
||||
$randomq = $DB->get_record('question', ['qtype' => 'random']);
|
||||
// Confirm we have a question set reference for the random question.
|
||||
$this->assertEquals(1, $DB->count_records('question_set_references', ['usingcontextid' => $context->id]));
|
||||
|
||||
quiz_delete_instance($quiz->id);
|
||||
|
||||
// Check that the random question was deleted.
|
||||
if ($randomq) {
|
||||
$this->assertEquals(0, $DB->count_records('question', ['id' => $randomq->id]));
|
||||
}
|
||||
// Check that the standard question was not deleted.
|
||||
$this->assertEquals(1, $DB->count_records('question', ['id' => $standardq->id]));
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ class all_calculated_for_qubaid_condition {
|
||||
protected function make_new_subq_stat_for($displaynumber, $slot, $subqid, $variant = null) {
|
||||
$slotstat = fullclone($this->for_subq($subqid, $variant));
|
||||
$slotstat->question->number = $this->for_slot($slot)->question->number;
|
||||
$slotstat->question->random = false;
|
||||
$slotstat->subqdisplayorder = $displaynumber;
|
||||
return $slotstat;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ class calculated {
|
||||
* @return null|string represents the pool of questions from which this question draws if it is random, or null if not.
|
||||
*/
|
||||
public function random_selector_string() {
|
||||
if ($this->question->qtype == 'random') {
|
||||
if ($this->question->random) {
|
||||
return $this->question->category .'/'. $this->question->questiontext;
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -67,7 +67,7 @@ class calculator {
|
||||
* Constructor.
|
||||
*
|
||||
* @param object[] questions to analyze, keyed by slot, also analyses sub questions for random questions.
|
||||
* we expect some extra fields - slot, maxmark and number on the full question data objects.
|
||||
* We expect some extra fields - slot, random, maxmark and number on the full question data objects.
|
||||
* @param \core\progress\base|null $progress the element to send progress messages to, default is {@link \core\progress\none}.
|
||||
*/
|
||||
public function __construct($questions, $progress = null) {
|
||||
@@ -194,7 +194,7 @@ class calculator {
|
||||
$this->initial_question_walker($this->stats->for_slot($slot));
|
||||
|
||||
// The rest of this loop is to finish working out where randomly selected question stats should be displayed.
|
||||
if ($this->stats->for_slot($slot)->question->qtype == 'random') {
|
||||
if ($this->stats->for_slot($slot)->question->random) {
|
||||
$randomselectorstring = $this->stats->for_slot($slot)->random_selector_string();
|
||||
if ($nextslot && ($randomselectorstring == $this->stats->for_slot($nextslot)->random_selector_string())) {
|
||||
continue; // Next loop iteration.
|
||||
@@ -210,10 +210,9 @@ class calculator {
|
||||
$this->progress->start_progress('', count($lateststeps), 1);
|
||||
foreach ($lateststeps as $step) {
|
||||
$this->progress->increment_progress();
|
||||
$israndomquestion = ($this->stats->for_slot($step->slot)->question->qtype == 'random');
|
||||
$this->secondary_steps_walker($step, $this->stats->for_slot($step->slot), $summarks);
|
||||
|
||||
if ($israndomquestion) {
|
||||
if ($this->stats->for_slot($step->slot)->question->random) {
|
||||
$this->secondary_steps_walker($step, $this->stats->for_subq($step->questionid), $summarks);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user