From 1da821bbde1348a67326ff7f676dff49182d4247 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Wed, 25 May 2011 23:46:08 +0100 Subject: [PATCH] MDL-27649 support question variants as a first-class concept in the question engine. --- lib/db/install.xml | 5 ++- lib/db/upgrade.php | 15 +++++++ local/qeupgradehelper/locallib.php | 1 + mod/quiz/startattempt.php | 2 +- question/behaviour/behaviourbase.php | 5 ++- question/behaviour/interactive/behaviour.php | 4 +- question/behaviour/missing/behaviour.php | 2 +- .../simpletest/testmissingbehaviour.php | 10 ++--- question/engine/datalib.php | 6 +++ question/engine/lib.php | 30 ++++++++++++++ question/engine/questionattempt.php | 37 +++++++++++++++--- question/engine/questionattemptstep.php | 4 ++ question/engine/questionusage.php | 39 +++++++++++++++++-- .../engine/simpletest/testquestionattempt.php | 34 ++++++++-------- .../engine/upgrade/behaviourconverters.php | 1 + .../db/simpletest/testupgradelibnewqe.php | 3 ++ question/type/calculated/question.php | 4 +- .../calculated/simpletest/testquestion.php | 10 ++--- .../db/simpletest/testupgradelibnewqe.php | 3 ++ question/type/calculatedmulti/question.php | 6 +-- .../simpletest/testquestion.php | 10 ++--- .../db/simpletest/testupgradelibnewqe.php | 3 ++ .../simpletest/testquestion.php | 10 ++--- .../db/simpletest/testupgradelibnewqe.php | 3 ++ .../db/simpletest/testupgradelibnewqe.php | 3 ++ .../db/simpletest/testupgradelibnewqe.php | 3 ++ question/type/match/question.php | 2 +- .../type/match/simpletest/testquestion.php | 18 ++++----- question/type/missingtype/question.php | 2 +- .../db/simpletest/testupgradelibnewqe.php | 6 +++ question/type/multianswer/question.php | 4 +- .../multianswer/simpletest/testquestion.php | 8 ++-- .../db/simpletest/testupgradelibnewqe.php | 13 +++++++ question/type/multichoice/question.php | 2 +- .../multichoice/simpletest/testquestion.php | 26 ++++++------- .../db/simpletest/testupgradelibnewqe.php | 2 + question/type/numerical/question.php | 2 +- question/type/numerical/questiontype.php | 2 + .../numerical/simpletest/testquestion.php | 6 +-- question/type/questionbase.php | 19 ++++++++- .../db/simpletest/testupgradelibnewqe.php | 4 ++ .../db/simpletest/testupgradelibnewqe.php | 3 ++ .../shortanswer/simpletest/testquestion.php | 2 +- .../db/simpletest/testupgradelibnewqe.php | 3 ++ .../truefalse/simpletest/testquestion.php | 2 +- version.php | 2 +- 46 files changed, 283 insertions(+), 98 deletions(-) diff --git a/lib/db/install.xml b/lib/db/install.xml index ec6d9415056..ae4edccc713 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1347,8 +1347,9 @@ - - + + + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 77fa9787c27..c634858c5d7 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -6414,6 +6414,21 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); upgrade_main_savepoint(true, 2011051212); } + if ($oldversion < 2011051213) { + // Define field variant to be added to question_attempts + $table = new xmldb_table('question_attempts'); + $field = new xmldb_field('variant', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, + XMLDB_NOTNULL, null, 1, 'questionid'); + + // Launch add field component + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached + upgrade_main_savepoint(true, 2011051213); + } + return true; } diff --git a/local/qeupgradehelper/locallib.php b/local/qeupgradehelper/locallib.php index ad4bbc48e1b..6bf873208a0 100755 --- a/local/qeupgradehelper/locallib.php +++ b/local/qeupgradehelper/locallib.php @@ -503,6 +503,7 @@ function local_qeupgradehelper_generate_unit_test($questionsessionid, $namesuffi echo " 'behaviour' => '{$quiz->preferredbehaviour}', 'questionid' => {$question->id}, + 'variant' => 1, 'maxmark' => {$question->maxmark}, 'minfraction' => 0, 'flagged' => 0, diff --git a/mod/quiz/startattempt.php b/mod/quiz/startattempt.php index a7e7fce5cfe..acf8c5ca36c 100644 --- a/mod/quiz/startattempt.php +++ b/mod/quiz/startattempt.php @@ -145,7 +145,7 @@ if (!($quiz->attemptonlast && $lastattempt)) { } // Start all the quetsions. - $quba->start_all_questions(time(), null); + $quba->start_all_questions(null, time(), null); // Update attempt layout. $newlayout = array(); diff --git a/question/behaviour/behaviourbase.php b/question/behaviour/behaviourbase.php index 581923c18f7..95c0e2a4dfe 100644 --- a/question/behaviour/behaviourbase.php +++ b/question/behaviour/behaviourbase.php @@ -334,9 +334,10 @@ abstract class question_behaviour { * * @param question_attempt_step $step the first step of the * question_attempt being started. + * @param int $variant which variant of the question to use. */ - public function init_first_step(question_attempt_step $step) { - $this->question->start_attempt($step); + public function init_first_step(question_attempt_step $step, $variant) { + $this->question->start_attempt($step, $variant); } /** diff --git a/question/behaviour/interactive/behaviour.php b/question/behaviour/interactive/behaviour.php index dfab4c3d6bd..976bb08e95f 100644 --- a/question/behaviour/interactive/behaviour.php +++ b/question/behaviour/interactive/behaviour.php @@ -138,8 +138,8 @@ class qbehaviour_interactive extends question_behaviour_with_save { } } - public function init_first_step(question_attempt_step $step) { - parent::init_first_step($step); + public function init_first_step(question_attempt_step $step, $variant) { + parent::init_first_step($step, $variant); $step->set_behaviour_var('_triesleft', count($this->question->hints) + 1); } diff --git a/question/behaviour/missing/behaviour.php b/question/behaviour/missing/behaviour.php index 69a2e01a090..1726e011166 100644 --- a/question/behaviour/missing/behaviour.php +++ b/question/behaviour/missing/behaviour.php @@ -53,7 +53,7 @@ class qbehaviour_missing extends question_behaviour { return ''; } - public function init_first_step(question_attempt_step $step) { + public function init_first_step(question_attempt_step $step, $variant) { throw new coding_exception('The behaviour used for this question is not available. ' . 'No processing is possible.'); } diff --git a/question/behaviour/missing/simpletest/testmissingbehaviour.php b/question/behaviour/missing/simpletest/testmissingbehaviour.php index 077f59be34a..9068eecb77c 100644 --- a/question/behaviour/missing/simpletest/testmissingbehaviour.php +++ b/question/behaviour/missing/simpletest/testmissingbehaviour.php @@ -42,7 +42,7 @@ class qbehaviour_missing_test extends UnitTestCase { $qa = new question_attempt(test_question_maker::make_a_truefalse_question(), 0); $behaviour = new qbehaviour_missing($qa, 'deferredfeedback'); $this->expectException(); - $behaviour->init_first_step(new question_attempt_step(array())); + $behaviour->init_first_step(new question_attempt_step(array()), 1); } public function test_missing_cannot_process() { @@ -62,15 +62,15 @@ class qbehaviour_missing_test extends UnitTestCase { public function test_render_missing() { $records = testing_db_record_builder::build_db_records(array( array('id', 'questionattemptid', 'contextid', 'questionusageid', 'slot', - 'behaviour', 'questionid', 'maxmark', 'minfraction', 'flagged', + 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', 'attemptstepid', 'sequencenumber', 'state', 'fraction', 'timecreated', 'userid', 'name', 'value'), - array(1, 1, 123, 1, 1, 'strangeunknown', -1, 2.0000000, 0.0000000, 0, '', '', '', + array(1, 1, 123, 1, 1, 'strangeunknown', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, '_order', '1,2,3'), - array(2, 1, 123, 1, 1, 'strangeunknown', -1, 2.0000000, 0.0000000, 0, '', '', '', + array(2, 1, 123, 1, 1, 'strangeunknown', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', 0.50, 1256233705, 1, '-submit', '1'), - array(3, 1, 123, 1, 1, 'strangeunknown', -1, 2.0000000, 0.0000000, 0, '', '', '', + array(3, 1, 123, 1, 1, 'strangeunknown', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', 0.50, 1256233705, 1, 'choice0', '1'), )); diff --git a/question/engine/datalib.php b/question/engine/datalib.php index dc7f78d66fd..3190a5c9db7 100644 --- a/question/engine/datalib.php +++ b/question/engine/datalib.php @@ -84,6 +84,7 @@ class question_engine_data_mapper { $record->slot = $qa->get_slot(); $record->behaviour = $qa->get_behaviour_name(); $record->questionid = $qa->get_question()->id; + $record->variant = $qa->get_variant(); $record->maxmark = $qa->get_max_mark(); $record->minfraction = $qa->get_min_fraction(); $record->flagged = $qa->is_flagged(); @@ -180,6 +181,7 @@ SELECT qa.slot, qa.behaviour, qa.questionid, + qa.variant, qa.maxmark, qa.minfraction, qa.flagged, @@ -236,6 +238,7 @@ SELECT qa.slot, qa.behaviour, qa.questionid, + qa.variant, qa.maxmark, qa.minfraction, qa.flagged, @@ -291,6 +294,7 @@ SELECT qa.slot, qa.behaviour, qa.questionid, + qa.variant, qa.maxmark, qa.minfraction, qa.flagged, @@ -549,6 +553,7 @@ SELECT qa.slot, qa.behaviour, qa.questionid, + qa.variant, qa.maxmark, qa.minfraction, qa.flagged, @@ -819,6 +824,7 @@ ORDER BY {$alias}qa.slot, {$alias}qa.behaviour, {$alias}qa.questionid, + {$alias}qa.variant, {$alias}qa.maxmark, {$alias}qa.minfraction, {$alias}qa.flagged, diff --git a/question/engine/lib.php b/question/engine/lib.php index e4692fc8cf2..d1e1d67a8dc 100644 --- a/question/engine/lib.php +++ b/question/engine/lib.php @@ -760,3 +760,33 @@ abstract class question_utils { self::$tens[$number / 10 % 10] . self::$units[$number % 10]; } } + + +/** + * The interface for strategies for controlling which variant of each question is used. + * + * @copyright 2010 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +interface question_variant_selection_strategy { + /** + * @param int $maxvariants the num + * @param string $seed data that can be used to controls how the variant is selected + * in a semi-random way. + * @return int the variant to use, a number betweeb 1 and $maxvariants inclusive. + */ + public function choose_variant($maxvariants, $seed); +} + + +/** + * A {@link question_variant_selection_strategy} that is completely random. + * + * @copyright 2010 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_variant_random_strategy implements question_variant_selection_strategy { + public function choose_variant($maxvariants, $seed) { + return rand(1, $maxvariants); + } +} diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php index dac444ee5e6..083bb062a2d 100644 --- a/question/engine/questionattempt.php +++ b/question/engine/questionattempt.php @@ -84,6 +84,9 @@ class question_attempt { /** @var question_definition the question this is an attempt at. */ protected $question; + /** @var int which variant of the question to use. */ + protected $variant; + /** @var number the maximum mark that can be scored at this question. */ protected $maxmark; @@ -162,6 +165,14 @@ class question_attempt { return $this->question; } + /** + * Get the variant of the question being used in a given slot. + * @return int the variant number. + */ + public function get_variant() { + return $this->variant; + } + /** * Set the number used to identify this question_attempt within the usage. * For internal use only. @@ -735,6 +746,16 @@ class question_attempt { $this->observer->notify_step_added($step, $this, key($this->steps)); } + /** + * Use a strategy to pick a variant. + * @param question_variant_selection_strategy $variantstrategy a strategy. + * @return int the selected variant. + */ + public function select_variant(question_variant_selection_strategy $variantstrategy) { + return $variantstrategy->choose_variant($this->get_question()->get_num_variants(), + $this->get_question()->get_variants_selection_seed()); + } + /** * Start this question attempt. * @@ -743,12 +764,17 @@ class question_attempt { * * @param string|question_behaviour $preferredbehaviour the name of the * desired archetypal behaviour, or an actual model instance. + * @param int $variant the variant of the question to start. Between 1 and + * $this->get_question()->get_num_variants() inclusive. * @param array $submitteddata optional, used when re-starting to keep the same initial state. * @param int $timestamp optional, the timstamp to record for this action. Defaults to now. * @param int $userid optional, the user to attribute this action to. Defaults to the current user. */ - public function start($preferredbehaviour, $submitteddata = array(), $timestamp = null, $userid = null) { + public function start($preferredbehaviour, $variant, $submitteddata = array(), + $timestamp = null, $userid = null) { + // Initialise the behaviour. + $this->variant = $variant; if (is_string($preferredbehaviour)) { $this->behaviour = $this->question->make_behaviour($this, $preferredbehaviour); @@ -766,7 +792,7 @@ class question_attempt { if ($submitteddata) { $this->question->apply_attempt_state($firststep); } else { - $this->behaviour->init_first_step($firststep); + $this->behaviour->init_first_step($firststep, $variant); } $this->add_step($firststep); @@ -786,7 +812,7 @@ class question_attempt { * defines the starting point. */ public function start_based_on(question_attempt $oldqa) { - $this->start($oldqa->behaviour, $oldqa->get_resume_data()); + $this->start($oldqa->behaviour, $oldqa->get_variant(), $oldqa->get_resume_data()); } /** @@ -1013,7 +1039,7 @@ class question_attempt { foreach ($oldqa->get_step_iterator() as $step) { if ($first) { $first = false; - $this->start($oldqa->behaviour, $step->get_all_data(), + $this->start($oldqa->behaviour, $oldqa->get_variant(), $step->get_all_data(), $step->get_timecreated(), $step->get_user_id()); } else { $this->process_action($step->get_submitted_data(), @@ -1109,6 +1135,7 @@ class question_attempt { null, $record->maxmark + 0); $qa->set_database_id($record->questionattemptid); $qa->set_number_in_usage($record->slot); + $qa->variant = $record->variant + 0; $qa->minfraction = $record->minfraction + 0; $qa->set_flagged($record->flagged); $qa->questionsummary = $record->questionsummary; @@ -1194,7 +1221,7 @@ class question_attempt_with_restricted_history extends question_attempt { public function process_action($submitteddata, $timestamp = null, $userid = null) { coding_exception('Cannot modify a question_attempt_with_restricted_history.'); } - public function start($preferredbehaviour, $submitteddata = array(), $timestamp = null, $userid = null) { + public function start($preferredbehaviour, $variant, $submitteddata = array(), $timestamp = null, $userid = null) { coding_exception('Cannot modify a question_attempt_with_restricted_history.'); } diff --git a/question/engine/questionattemptstep.php b/question/engine/questionattemptstep.php index eb7d549b4f0..6d4148b8c2f 100644 --- a/question/engine/questionattemptstep.php +++ b/question/engine/questionattemptstep.php @@ -101,6 +101,10 @@ class question_attempt_step { */ public function __construct($data = array(), $timecreated = null, $userid = null) { global $USER; + + if (!is_array($data)) { + echo format_backtrace(debug_backtrace()); + } $this->state = question_state::$unprocessed; $this->data = $data; if (is_null($timecreated)) { diff --git a/question/engine/questionusage.php b/question/engine/questionusage.php index a1144f3f427..5811c8981ea 100644 --- a/question/engine/questionusage.php +++ b/question/engine/questionusage.php @@ -407,24 +407,55 @@ class question_usage_by_activity { return $this->get_question_attempt($slot)->get_field_prefix(); } + /** + * Get the number of variants available for the question in this slot. + * @param int $slot the number used to identify this question within this usage. + * @return int the number of variants available. + */ + public function get_num_variants($slot) { + return $this->get_question_attempt($slot)->get_question()->get_num_variants(); + } + + /** + * Get the variant of the question being used in a given slot. + * @param int $slot the number used to identify this question within this usage. + * @return int the variant of this question that is being used. + */ + public function get_variant($slot) { + return $this->get_question_attempt($slot)->get_variant(); + } + /** * Start the attempt at a question that has been added to this usage. * @param int $slot the number used to identify this question within this usage. + * @param int $variant which variant of the question to use. Must be between + * 1 and ->get_num_variants($slot) inclusive. If not give, a variant is + * chosen at random. */ - public function start_question($slot) { + public function start_question($slot, $variant = null) { + if (is_null($variant)) { + $variant = rand(1, $this->get_num_variants($slot)); + } + $qa = $this->get_question_attempt($slot); - $qa->start($this->preferredbehaviour); + $qa->start($this->preferredbehaviour, $variant); $this->observer->notify_attempt_modified($qa); } /** * Start the attempt at all questions that has been added to this usage. + * @param question_variant_selection_strategy how to pick which variant of each question to use. * @param int $timestamp optional, the timstamp to record for this action. Defaults to now. * @param int $userid optional, the user to attribute this action to. Defaults to the current user. */ - public function start_all_questions($timestamp = null, $userid = null) { + public function start_all_questions(question_variant_selection_strategy $variantstrategy = null, + $timestamp = null, $userid = null) { + if (is_null($variantstrategy)) { + $variantstrategy = new question_variant_random_strategy(); + } + foreach ($this->questionattempts as $qa) { - $qa->start($this->preferredbehaviour); + $qa->start($this->preferredbehaviour, $qa->select_variant($variantstrategy)); $this->observer->notify_attempt_modified($qa); } } diff --git a/question/engine/simpletest/testquestionattempt.php b/question/engine/simpletest/testquestionattempt.php index 62215de14c3..c82e6bf7736 100644 --- a/question/engine/simpletest/testquestionattempt.php +++ b/question/engine/simpletest/testquestionattempt.php @@ -263,18 +263,18 @@ class question_attempt_db_test extends data_loading_method_test_base { public function test_load() { $records = testing_db_record_builder::build_db_records(array( array('id', 'questionattemptid', 'contextid', 'questionusageid', 'slot', - 'behaviour', 'questionid', 'maxmark', 'minfraction', 'flagged', - 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', - 'attemptstepid', 'sequencenumber', 'state', 'fraction', - 'timecreated', 'userid', 'name', 'value'), - array(1, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), - array(2, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'), - array(3, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'), - array(4, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, 3, 'complete', null, 1256233715, 1, 'answer', '1'), - array(5, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 4, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'), - array(6, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-comment', 'Not good enough!'), - array(7, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-mark', '1'), - array(8, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-maxmark', '2'), + 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', + 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', + 'attemptstepid', 'sequencenumber', 'state', 'fraction', + 'timecreated', 'userid', 'name', 'value'), + array(1, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), + array(2, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'), + array(3, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'), + array(4, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, 3, 'complete', null, 1256233715, 1, 'answer', '1'), + array(5, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 4, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'), + array(6, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-comment', 'Not good enough!'), + array(7, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-mark', '1'), + array(8, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-maxmark', '2'), )); $question = test_question_maker::make_a_truefalse_question(); @@ -336,11 +336,11 @@ class question_attempt_db_test extends data_loading_method_test_base { public function test_load_missing_question() { $records = testing_db_record_builder::build_db_records(array( array('id', 'questionattemptid', 'contextid', 'questionusageid', 'slot', - 'behaviour', 'questionid', 'maxmark', 'minfraction', 'flagged', - 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', - 'attemptstepid', 'sequencenumber', 'state', 'fraction', - 'timecreated', 'userid', 'name', 'value'), - array(1, 1, 123, 1, 1, 'deferredfeedback', -1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), + 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged', + 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified', + 'attemptstepid', 'sequencenumber', 'state', 'fraction', + 'timecreated', 'userid', 'name', 'value'), + array(1, 1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null), )); question_bank::start_unit_test(); diff --git a/question/engine/upgrade/behaviourconverters.php b/question/engine/upgrade/behaviourconverters.php index 2908ef3e4d2..3a9f50ad62a 100644 --- a/question/engine/upgrade/behaviourconverters.php +++ b/question/engine/upgrade/behaviourconverters.php @@ -131,6 +131,7 @@ abstract class question_behaviour_attempt_updater { $qa = new stdClass(); $qa->questionid = $this->question->id; + $qa->variant = 1; $qa->behaviour = $this->behaviour_name(); $qa->questionsummary = $this->qtypeupdater->question_summary($this->question); $qa->rightanswer = $this->qtypeupdater->right_answer($this->question); diff --git a/question/type/calculated/db/simpletest/testupgradelibnewqe.php b/question/type/calculated/db/simpletest/testupgradelibnewqe.php index ebaafc1b5b1..da03ef369fc 100644 --- a/question/type/calculated/db/simpletest/testupgradelibnewqe.php +++ b/question/type/calculated/db/simpletest/testupgradelibnewqe.php @@ -200,6 +200,7 @@ class qtype_calculated_attempt_upgrader_test extends question_attempt_upgrader_t $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 18, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -422,6 +423,7 @@ Remember to type a unit.', $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 18, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -651,6 +653,7 @@ Remember to type a unit.', $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 18, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/calculated/question.php b/question/type/calculated/question.php index 327b365235e..5ed0fbe4f75 100644 --- a/question/type/calculated/question.php +++ b/question/type/calculated/question.php @@ -50,9 +50,9 @@ class qtype_calculated_question extends qtype_numerical_question */ public $synchronised; - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { qtype_calculated_question_helper::start_attempt($this, $step); - parent::start_attempt($step); + parent::start_attempt($step, $variant); } public function apply_attempt_state(question_attempt_step $step) { diff --git a/question/type/calculated/simpletest/testquestion.php b/question/type/calculated/simpletest/testquestion.php index d368e987258..6df2ca5b016 100644 --- a/question/type/calculated/simpletest/testquestion.php +++ b/question/type/calculated/simpletest/testquestion.php @@ -55,7 +55,7 @@ class qtype_calculated_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array(0, question_state::$gradedwrong), @@ -66,7 +66,7 @@ class qtype_calculated_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array('answer' => $values['a'] + $values['b']), @@ -75,7 +75,7 @@ class qtype_calculated_question_test extends UnitTestCase { public function test_get_question_summary() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $qsummary = $question->get_question_summary(); @@ -84,7 +84,7 @@ class qtype_calculated_question_test extends UnitTestCase { public function test_summarise_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual('3.1', $question->summarise_response(array('answer' => '3.1'))); @@ -92,7 +92,7 @@ class qtype_calculated_question_test extends UnitTestCase { public function test_classify_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array( diff --git a/question/type/calculatedmulti/db/simpletest/testupgradelibnewqe.php b/question/type/calculatedmulti/db/simpletest/testupgradelibnewqe.php index 46ba068a1bc..ade8c716811 100644 --- a/question/type/calculatedmulti/db/simpletest/testupgradelibnewqe.php +++ b/question/type/calculatedmulti/db/simpletest/testupgradelibnewqe.php @@ -227,6 +227,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 17, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -460,6 +461,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 17, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -737,6 +739,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 17, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/calculatedmulti/question.php b/question/type/calculatedmulti/question.php index 99ac4a0c91f..8b497f46b1f 100644 --- a/question/type/calculatedmulti/question.php +++ b/question/type/calculatedmulti/question.php @@ -51,7 +51,7 @@ class qtype_calculatedmulti_single_question extends qtype_multichoice_single_que */ public $synchronised; - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { qtype_calculated_question_helper::start_attempt($this, $step); parent::start_attempt($step); } @@ -88,9 +88,9 @@ class qtype_calculatedmulti_multi_question extends qtype_multichoice_multi_quest */ public $synchronised; - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { qtype_calculated_question_helper::start_attempt($this, $step); - parent::start_attempt($step); + parent::start_attempt($step, $variant); } public function apply_attempt_state(question_attempt_step $step) { diff --git a/question/type/calculatedmulti/simpletest/testquestion.php b/question/type/calculatedmulti/simpletest/testquestion.php index f661fd57cb9..f71fa1abc8c 100644 --- a/question/type/calculatedmulti/simpletest/testquestion.php +++ b/question/type/calculatedmulti/simpletest/testquestion.php @@ -55,7 +55,7 @@ class qtype_calculatedmulti_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array(0, question_state::$gradedwrong), @@ -66,7 +66,7 @@ class qtype_calculatedmulti_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array('answer' => $values['a'] + $values['b']), @@ -75,7 +75,7 @@ class qtype_calculatedmulti_question_test extends UnitTestCase { public function test_get_question_summary() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $qsummary = $question->get_question_summary(); @@ -84,7 +84,7 @@ class qtype_calculatedmulti_question_test extends UnitTestCase { public function test_summarise_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual('3.1', $question->summarise_response(array('answer' => '3.1'))); @@ -92,7 +92,7 @@ class qtype_calculatedmulti_question_test extends UnitTestCase { public function test_classify_response() { $question = test_question_maker::make_question('calculated'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array( diff --git a/question/type/calculatedsimple/db/simpletest/testupgradelibnewqe.php b/question/type/calculatedsimple/db/simpletest/testupgradelibnewqe.php index 3b60b54b1ec..191d8194d5b 100644 --- a/question/type/calculatedsimple/db/simpletest/testupgradelibnewqe.php +++ b/question/type/calculatedsimple/db/simpletest/testupgradelibnewqe.php @@ -191,6 +191,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 16, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -400,6 +401,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 16, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -601,6 +603,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr $expectedqa = (object) array( 'behaviour' => 'adaptive', 'questionid' => 16, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/calculatedsimple/simpletest/testquestion.php b/question/type/calculatedsimple/simpletest/testquestion.php index 99a78390bed..fb121990056 100644 --- a/question/type/calculatedsimple/simpletest/testquestion.php +++ b/question/type/calculatedsimple/simpletest/testquestion.php @@ -55,7 +55,7 @@ class qtype_calculatedsimple_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_question('calculatedsimple'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array(0, question_state::$gradedwrong), @@ -66,7 +66,7 @@ class qtype_calculatedsimple_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_question('calculatedsimple'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array('answer' => $values['a'] + $values['b']), @@ -75,7 +75,7 @@ class qtype_calculatedsimple_question_test extends UnitTestCase { public function test_get_question_summary() { $question = test_question_maker::make_question('calculatedsimple'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $qsummary = $question->get_question_summary(); @@ -84,7 +84,7 @@ class qtype_calculatedsimple_question_test extends UnitTestCase { public function test_summarise_response() { $question = test_question_maker::make_question('calculatedsimple'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual('3.1', $question->summarise_response(array('answer' => '3.1'))); @@ -92,7 +92,7 @@ class qtype_calculatedsimple_question_test extends UnitTestCase { public function test_classify_response() { $question = test_question_maker::make_question('calculatedsimple'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $values = $question->vs->get_values(); $this->assertEqual(array( diff --git a/question/type/description/db/simpletest/testupgradelibnewqe.php b/question/type/description/db/simpletest/testupgradelibnewqe.php index b9293df4e92..bf706756d80 100644 --- a/question/type/description/db/simpletest/testupgradelibnewqe.php +++ b/question/type/description/db/simpletest/testupgradelibnewqe.php @@ -153,6 +153,7 @@ class qtype_description_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'informationitem', 'questionid' => 4940, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -298,6 +299,7 @@ class qtype_description_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'informationitem', 'questionid' => 8492, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, @@ -433,6 +435,7 @@ class qtype_description_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'informationitem', 'questionid' => 8719, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/essay/db/simpletest/testupgradelibnewqe.php b/question/type/essay/db/simpletest/testupgradelibnewqe.php index 141de82b312..cea94702c49 100644 --- a/question/type/essay/db/simpletest/testupgradelibnewqe.php +++ b/question/type/essay/db/simpletest/testupgradelibnewqe.php @@ -214,6 +214,7 @@ class qtype_essay_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'manualgraded', 'questionid' => 90056, + 'variant' => 1, 'maxmark' => 2, 'minfraction' => 0, 'flagged' => 0, @@ -412,6 +413,7 @@ class qtype_essay_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'manualgraded', 'questionid' => 3729, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, @@ -539,6 +541,7 @@ class qtype_essay_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'manualgraded', 'questionid' => 3729, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/match/db/simpletest/testupgradelibnewqe.php b/question/type/match/db/simpletest/testupgradelibnewqe.php index 479bfe7d080..6c8003cbc7f 100644 --- a/question/type/match/db/simpletest/testupgradelibnewqe.php +++ b/question/type/match/db/simpletest/testupgradelibnewqe.php @@ -226,6 +226,7 @@ class qtype_match_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 695, + 'variant' => 1, 'maxmark' => 3, 'minfraction' => 0, 'flagged' => 0, @@ -442,6 +443,7 @@ class qtype_match_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 738, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -705,6 +707,7 @@ class qtype_match_attempt_upgrader_test extends question_attempt_upgrader_test_b $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 11135, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/match/question.php b/question/type/match/question.php index d7d3a820d26..ab4b36813de 100644 --- a/question/type/match/question.php +++ b/question/type/match/question.php @@ -56,7 +56,7 @@ class qtype_match_question extends question_graded_automatically_with_countback /** @var array shuffled choice indexes. */ protected $choiceorder; - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { $this->stemorder = array_keys($this->stems); if ($this->shufflestems) { shuffle($this->stemorder); diff --git a/question/type/match/simpletest/testquestion.php b/question/type/match/simpletest/testquestion.php index fa2e62060dc..c734088bf8e 100644 --- a/question/type/match/simpletest/testquestion.php +++ b/question/type/match/simpletest/testquestion.php @@ -39,7 +39,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_get_expected_data() { $question = test_question_maker::make_a_matching_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array('sub0' => PARAM_INT, 'sub1' => PARAM_INT, 'sub2' => PARAM_INT, 'sub3' => PARAM_INT), $question->get_expected_data()); @@ -47,7 +47,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_is_complete_response() { $question = test_question_maker::make_a_matching_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertFalse($question->is_complete_response(array())); $this->assertFalse($question->is_complete_response( @@ -59,7 +59,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_is_gradable_response() { $question = test_question_maker::make_a_matching_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertFalse($question->is_gradable_response(array())); $this->assertFalse($question->is_gradable_response( @@ -73,7 +73,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_is_same_response() { $question = test_question_maker::make_a_matching_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertTrue($question->is_same_response( array(), @@ -99,7 +99,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_a_matching_question(); $question->shufflestems = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $choiceorder = $question->get_choice_order(); $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); @@ -119,7 +119,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_a_matching_question(); $question->shufflestems = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $choiceorder = $question->get_choice_order(); $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); @@ -131,7 +131,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_get_question_summary() { $match = test_question_maker::make_a_matching_question(); - $match->start_attempt(new question_attempt_step()); + $match->start_attempt(new question_attempt_step(), 1); $qsummary = $match->get_question_summary(); $this->assertPattern('/' . preg_quote($match->questiontext) . '/', $qsummary); foreach ($match->stems as $stem) { @@ -145,7 +145,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_summarise_response() { $match = test_question_maker::make_a_matching_question(); $match->shufflestems = false; - $match->start_attempt(new question_attempt_step()); + $match->start_attempt(new question_attempt_step(), 1); $summary = $match->summarise_response(array('sub0' => 2, 'sub1' => 1)); @@ -155,7 +155,7 @@ class qtype_match_question_test extends UnitTestCase { public function test_classify_response() { $match = test_question_maker::make_a_matching_question(); $match->shufflestems = false; - $match->start_attempt(new question_attempt_step()); + $match->start_attempt(new question_attempt_step(), 1); $choiceorder = $match->get_choice_order(); $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); diff --git a/question/type/missingtype/question.php b/question/type/missingtype/question.php index 884c346b8cd..a46f1bd5b33 100644 --- a/question/type/missingtype/question.php +++ b/question/type/missingtype/question.php @@ -76,7 +76,7 @@ class qtype_missingtype_question extends question_definition return array(); } - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { throw new coding_exception('This question is of a type that is not installed ' . 'on your system. No processing is possible.'); } diff --git a/question/type/multianswer/db/simpletest/testupgradelibnewqe.php b/question/type/multianswer/db/simpletest/testupgradelibnewqe.php index 6d9b54948ba..4b870d2c95e 100644 --- a/question/type/multianswer/db/simpletest/testupgradelibnewqe.php +++ b/question/type/multianswer/db/simpletest/testupgradelibnewqe.php @@ -201,6 +201,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 28, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -392,6 +393,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 28, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -598,6 +600,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 28, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -1266,6 +1269,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 19, + 'variant' => 1, 'maxmark' => 13.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -1939,6 +1943,7 @@ b) What grade would you give it? _____', $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 19, + 'variant' => 1, 'maxmark' => 13.0000000, 'minfraction' => 0, 'flagged' => 0, @@ -2632,6 +2637,7 @@ b) What grade would you give it? _____', $expectedqa = (object) array( 'behaviour' => 'adaptivenopenalty', 'questionid' => 19, + 'variant' => 1, 'maxmark' => 13.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/multianswer/question.php b/question/type/multianswer/question.php index d8f8c898ff7..42a8b8fee5e 100644 --- a/question/type/multianswer/question.php +++ b/question/type/multianswer/question.php @@ -65,9 +65,9 @@ class qtype_multianswer_question extends question_graded_automatically { return new question_attempt_step_subquestion_adapter($step, 'sub' . $i . '_'); } - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { foreach ($this->subquestions as $i => $subq) { - $subq->start_attempt($this->get_substep($step, $i)); + $subq->start_attempt($this->get_substep($step, $i), $variant); } } diff --git a/question/type/multianswer/simpletest/testquestion.php b/question/type/multianswer/simpletest/testquestion.php index 0550b776922..b9c21e60d0f 100644 --- a/question/type/multianswer/simpletest/testquestion.php +++ b/question/type/multianswer/simpletest/testquestion.php @@ -65,7 +65,7 @@ class qtype_multianswer_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_question('multianswer'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $rightchoice = $question->subquestions[2]->get_correct_response(); @@ -81,7 +81,7 @@ class qtype_multianswer_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_question('multianswer'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $rightchoice = $question->subquestions[2]->get_correct_response(); @@ -95,7 +95,7 @@ class qtype_multianswer_question_test extends UnitTestCase { // Bit of a hack to make testing easier. $question->subquestions[2]->shuffleanswers = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $qsummary = $question->get_question_summary(); $this->assertEqual('Complete this opening line of verse: "The _____ and the ' . @@ -104,7 +104,7 @@ class qtype_multianswer_question_test extends UnitTestCase { public function test_summarise_response() { $question = test_question_maker::make_question('multianswer'); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $rightchoice = $question->subquestions[2]->get_correct_response(); diff --git a/question/type/multichoice/db/simpletest/testupgradelibnewqe.php b/question/type/multichoice/db/simpletest/testupgradelibnewqe.php index 67c32e37367..b99c7cae7cc 100644 --- a/question/type/multichoice/db/simpletest/testupgradelibnewqe.php +++ b/question/type/multichoice/db/simpletest/testupgradelibnewqe.php @@ -235,6 +235,7 @@ class qtype_multichoice_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 2, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -410,6 +411,7 @@ class qtype_multichoice_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 72, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -604,6 +606,7 @@ class qtype_multichoice_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 218, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -826,6 +829,7 @@ class qtype_multichoice_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 2855, + 'variant' => 1, 'maxmark' => 5, 'minfraction' => 0, 'flagged' => 0, @@ -983,6 +987,7 @@ class qtype_multichoice_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 72, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -1176,6 +1181,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 179, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -1413,6 +1419,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 26132, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, @@ -1644,6 +1651,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 60137, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -1872,6 +1880,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 163, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -2084,6 +2093,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 89040, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -2298,6 +2308,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 3863, + 'variant' => 1, 'maxmark' => 5, 'minfraction' => 0, 'flagged' => 0, @@ -2506,6 +2517,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 247, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, @@ -2716,6 +2728,7 @@ public function test_multichoice_deferredfeedback_qsession140() { $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 242, + 'variant' => 1, 'maxmark' => 0, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/multichoice/question.php b/question/type/multichoice/question.php index a20fe43c9cb..dd587ba5fc3 100644 --- a/question/type/multichoice/question.php +++ b/question/type/multichoice/question.php @@ -54,7 +54,7 @@ abstract class qtype_multichoice_base extends question_graded_automatically { protected $order = null; - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { $this->order = array_keys($this->answers); if ($this->shuffleanswers) { shuffle($this->order); diff --git a/question/type/multichoice/simpletest/testquestion.php b/question/type/multichoice/simpletest/testquestion.php index 57f1a64c86e..190a04b7e10 100644 --- a/question/type/multichoice/simpletest/testquestion.php +++ b/question/type/multichoice/simpletest/testquestion.php @@ -61,7 +61,7 @@ class qtype_multichoice_single_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_a_multichoice_single_question(); $question->shuffleanswers = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array(1, question_state::$gradedright), $question->grade_response(array('answer' => 0))); @@ -94,7 +94,7 @@ class qtype_multichoice_single_question_test extends UnitTestCase { 16 => new question_answer(16, '6', -1, '', FORMAT_HTML), ); - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); list($grade, $state) = $mc->grade_response( array('choice0' => 1, 'choice2' => 1, 'choice4' => 1)); @@ -105,7 +105,7 @@ class qtype_multichoice_single_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_a_multichoice_single_question(); $question->shuffleanswers = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array('answer' => 0), $question->get_correct_response()); @@ -114,7 +114,7 @@ class qtype_multichoice_single_question_test extends UnitTestCase { public function test_summarise_response() { $mc = test_question_maker::make_a_multichoice_single_question(); $mc->shuffleanswers = false; - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); $summary = $mc->summarise_response(array('answer' => 0), test_question_maker::get_a_qa($mc)); @@ -125,7 +125,7 @@ class qtype_multichoice_single_question_test extends UnitTestCase { public function test_classify_response() { $mc = test_question_maker::make_a_multichoice_single_question(); $mc->shuffleanswers = false; - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( $mc->id => new question_classified_response(14, 'B', -0.3333333), @@ -148,7 +148,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_get_expected_data() { $question = test_question_maker::make_a_multichoice_multi_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array('choice0' => PARAM_BOOL, 'choice1' => PARAM_BOOL, 'choice2' => PARAM_BOOL, 'choice3' => PARAM_BOOL), $question->get_expected_data()); @@ -156,7 +156,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_is_complete_response() { $question = test_question_maker::make_a_multichoice_multi_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertFalse($question->is_complete_response(array())); $this->assertFalse($question->is_complete_response( @@ -168,7 +168,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_is_gradable_response() { $question = test_question_maker::make_a_multichoice_multi_question(); - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertFalse($question->is_gradable_response(array())); $this->assertFalse($question->is_gradable_response( @@ -181,7 +181,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_grading() { $question = test_question_maker::make_a_multichoice_multi_question(); $question->shuffleanswers = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array(1, question_state::$gradedright), $question->grade_response(array('choice0' => '1', 'choice2' => '1'))); @@ -197,7 +197,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_get_correct_response() { $question = test_question_maker::make_a_multichoice_multi_question(); $question->shuffleanswers = false; - $question->start_attempt(new question_attempt_step()); + $question->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array('choice0' => '1', 'choice2' => '1'), $question->get_correct_response()); @@ -205,7 +205,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_get_question_summary() { $mc = test_question_maker::make_a_multichoice_single_question(); - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); $qsummary = $mc->get_question_summary(); @@ -218,7 +218,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_summarise_response() { $mc = test_question_maker::make_a_multichoice_multi_question(); $mc->shuffleanswers = false; - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); $summary = $mc->summarise_response(array('choice1' => 1, 'choice2' => 1), test_question_maker::get_a_qa($mc)); @@ -229,7 +229,7 @@ class qtype_multichoice_multi_question_test extends UnitTestCase { public function test_classify_response() { $mc = test_question_maker::make_a_multichoice_multi_question(); $mc->shuffleanswers = false; - $mc->start_attempt(new question_attempt_step()); + $mc->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( 13 => new question_classified_response(13, 'A', 0.5), diff --git a/question/type/numerical/db/simpletest/testupgradelibnewqe.php b/question/type/numerical/db/simpletest/testupgradelibnewqe.php index 6b4a6e65bf0..1254ba3b190 100644 --- a/question/type/numerical/db/simpletest/testupgradelibnewqe.php +++ b/question/type/numerical/db/simpletest/testupgradelibnewqe.php @@ -225,6 +225,7 @@ class qtype_numerical_attempt_upgrader_test extends question_attempt_upgrader_te $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 4165, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -421,6 +422,7 @@ class qtype_numerical_attempt_upgrader_test extends question_attempt_upgrader_te $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 15, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/numerical/question.php b/question/type/numerical/question.php index 2300c6cd3d9..7adacae84a2 100644 --- a/question/type/numerical/question.php +++ b/question/type/numerical/question.php @@ -57,7 +57,7 @@ class qtype_numerical_question extends question_graded_automatically { return $expected; } - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { $step->set_qt_var('_separators', $this->ap->get_point() . '$' . $this->ap->get_separator()); } diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index 2852c3d5af2..b8c8b3863a8 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -27,6 +27,8 @@ defined('MOODLE_INTERNAL') || die(); +require_once($CFG->dirroot . '/question/type/numerical/question.php'); + /** * The numerical question type class. diff --git a/question/type/numerical/simpletest/testquestion.php b/question/type/numerical/simpletest/testquestion.php index f2f37d202e9..2a1fe39bc31 100644 --- a/question/type/numerical/simpletest/testquestion.php +++ b/question/type/numerical/simpletest/testquestion.php @@ -174,7 +174,7 @@ class qtype_numerical_question_test extends UnitTestCase { public function test_classify_response() { $num = test_question_maker::make_question('numerical'); - $num->start_attempt(new question_attempt_step()); + $num->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( new question_classified_response(15, '3.1', 0.0)), @@ -192,7 +192,7 @@ class qtype_numerical_question_test extends UnitTestCase { public function test_classify_response_unit() { $num = test_question_maker::make_question('numerical', 'unit'); - $num->start_attempt(new question_attempt_step()); + $num->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( new question_classified_response(13, '1.25', 0.5)), @@ -219,7 +219,7 @@ class qtype_numerical_question_test extends UnitTestCase { public function test_classify_response_currency() { $num = test_question_maker::make_question('numerical', 'currency'); - $num->start_attempt(new question_attempt_step()); + $num->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( new question_classified_response(14, '$100', 0)), diff --git a/question/type/questionbase.php b/question/type/questionbase.php index 07dc2aa411d..2dae4879d61 100644 --- a/question/type/questionbase.php +++ b/question/type/questionbase.php @@ -157,8 +157,10 @@ abstract class question_definition { * * @param question_attempt_step The first step of the {@link question_attempt} * being started. Can be used to store state. + * @param int $varant which variant of this question to start. Will be between + * 1 and {@link get_num_variants()} inclusive. */ - public function start_attempt(question_attempt_step $step) { + public function start_attempt(question_attempt_step $step, $variant) { } /** @@ -190,6 +192,21 @@ abstract class question_definition { return $this->html_to_text($this->questiontext, $this->questiontextformat); } + /** + * @return int the number of vaiants that this question has. + */ + public function get_num_variants() { + return 1; + } + + /** + * @return string that can be used to seed the pseudo-random selection of a + * variant. + */ + public function get_variants_selection_seed() { + return $this->stamp; + } + /** * Some questions can return a negative mark if the student gets it wrong. * diff --git a/question/type/random/db/simpletest/testupgradelibnewqe.php b/question/type/random/db/simpletest/testupgradelibnewqe.php index 4986c17c80c..164e916d47f 100644 --- a/question/type/random/db/simpletest/testupgradelibnewqe.php +++ b/question/type/random/db/simpletest/testupgradelibnewqe.php @@ -228,6 +228,7 @@ class qtype_random_attempt_upgrader_test extends question_attempt_upgrader_test_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 34999, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -468,6 +469,7 @@ class qtype_random_attempt_upgrader_test extends question_attempt_upgrader_test_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 98355, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -745,6 +747,7 @@ class qtype_random_attempt_upgrader_test extends question_attempt_upgrader_test_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 83248, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -941,6 +944,7 @@ class qtype_random_attempt_upgrader_test extends question_attempt_upgrader_test_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 14, + 'variant' => 1, 'maxmark' => 1.0000000, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/shortanswer/db/simpletest/testupgradelibnewqe.php b/question/type/shortanswer/db/simpletest/testupgradelibnewqe.php index c327bd8f4b9..1b16af69ef9 100644 --- a/question/type/shortanswer/db/simpletest/testupgradelibnewqe.php +++ b/question/type/shortanswer/db/simpletest/testupgradelibnewqe.php @@ -209,6 +209,7 @@ class qtype_shortanswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 4239, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -390,6 +391,7 @@ class qtype_shortanswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 10216, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -589,6 +591,7 @@ class qtype_shortanswer_attempt_upgrader_test extends question_attempt_upgrader_ $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 4184, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/shortanswer/simpletest/testquestion.php b/question/type/shortanswer/simpletest/testquestion.php index 0aa7095ca32..afd66efb5fa 100644 --- a/question/type/shortanswer/simpletest/testquestion.php +++ b/question/type/shortanswer/simpletest/testquestion.php @@ -159,7 +159,7 @@ class qtype_shortanswer_question_test extends UnitTestCase { public function test_classify_response() { $sa = test_question_maker::make_a_shortanswer_question(); - $sa->start_attempt(new question_attempt_step()); + $sa->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( new question_classified_response(13, 'frog', 1.0)), diff --git a/question/type/truefalse/db/simpletest/testupgradelibnewqe.php b/question/type/truefalse/db/simpletest/testupgradelibnewqe.php index e62e89be85e..2f0640867e9 100644 --- a/question/type/truefalse/db/simpletest/testupgradelibnewqe.php +++ b/question/type/truefalse/db/simpletest/testupgradelibnewqe.php @@ -189,6 +189,7 @@ class qtype_truefalse_attempt_upgrader_test extends question_attempt_upgrader_te $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 3865, + 'variant' => 1, 'maxmark' => 5, 'minfraction' => 0, 'flagged' => 0, @@ -375,6 +376,7 @@ class qtype_truefalse_attempt_upgrader_test extends question_attempt_upgrader_te $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 9062, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, @@ -543,6 +545,7 @@ class qtype_truefalse_attempt_upgrader_test extends question_attempt_upgrader_te $expectedqa = (object) array( 'behaviour' => 'deferredfeedback', 'questionid' => 111, + 'variant' => 1, 'maxmark' => 1, 'minfraction' => 0, 'flagged' => 0, diff --git a/question/type/truefalse/simpletest/testquestion.php b/question/type/truefalse/simpletest/testquestion.php index bafefa949e7..085cfe8da1d 100644 --- a/question/type/truefalse/simpletest/testquestion.php +++ b/question/type/truefalse/simpletest/testquestion.php @@ -92,7 +92,7 @@ class qtype_truefalse_question_test extends UnitTestCase { public function test_classify_response() { $tf = test_question_maker::make_a_truefalse_question(); - $tf->start_attempt(new question_attempt_step()); + $tf->start_attempt(new question_attempt_step(), 1); $this->assertEqual(array( $tf->id => new question_classified_response( diff --git a/version.php b/version.php index 967b26dcaf2..05687658177 100644 --- a/version.php +++ b/version.php @@ -30,7 +30,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2011051212.00; // YYYYMMDD = weekly release date of this DEV branch +$version = 2011051213.00; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes