mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-67183' of git://github.com/timhunt/moodle
This commit is contained in:
commit
7380c31afe
@ -1162,7 +1162,7 @@ class quiz_attempt {
|
||||
return $options;
|
||||
}
|
||||
|
||||
$question = $this->quba->get_question($slot);
|
||||
$question = $this->quba->get_question($slot, false);
|
||||
if (!question_has_capability_on($question, 'edit', $question->category)) {
|
||||
return $options;
|
||||
}
|
||||
@ -1267,7 +1267,7 @@ class quiz_attempt {
|
||||
* question length, which could theoretically be greater than one.
|
||||
*/
|
||||
public function is_real_question($slot) {
|
||||
return $this->quba->get_question($slot)->length;
|
||||
return $this->quba->get_question($slot, false)->length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1368,7 +1368,7 @@ class quiz_attempt {
|
||||
* by the quiz.
|
||||
*/
|
||||
public function get_question_name($slot) {
|
||||
return $this->quba->get_question($slot)->name;
|
||||
return $this->quba->get_question($slot, false)->name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1441,7 +1441,7 @@ class quiz_attempt {
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function get_question_type_name($slot) {
|
||||
return $this->quba->get_question($slot)->get_type_name();
|
||||
return $this->quba->get_question($slot, false)->get_type_name();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1767,7 +1767,7 @@ class quiz_attempt {
|
||||
* @return question_attempt the placeholder question attempt.
|
||||
*/
|
||||
protected function make_blocked_question_placeholder($slot) {
|
||||
$replacedquestion = $this->get_question_attempt($slot)->get_question();
|
||||
$replacedquestion = $this->get_question_attempt($slot)->get_question(false);
|
||||
|
||||
question_bank::load_question_definition_classes('description');
|
||||
$question = new qtype_description_question();
|
||||
@ -2690,7 +2690,7 @@ abstract class quiz_nav_panel_base {
|
||||
}
|
||||
|
||||
protected function get_state_string(question_attempt $qa, $showcorrectness) {
|
||||
if ($qa->get_question()->length > 0) {
|
||||
if ($qa->get_question(false)->length > 0) {
|
||||
return $qa->get_state_string($showcorrectness);
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ if (data_submitted() && confirm_sesskey()) {
|
||||
|
||||
// Log this action.
|
||||
$params = array(
|
||||
'objectid' => $attemptobj->get_question_attempt($slot)->get_question()->id,
|
||||
'objectid' => $attemptobj->get_question_attempt($slot)->get_question_id(),
|
||||
'courseid' => $attemptobj->get_courseid(),
|
||||
'context' => context_module::instance($attemptobj->get_cmid()),
|
||||
'other' => array(
|
||||
|
@ -316,7 +316,7 @@ function quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt) {
|
||||
|
||||
$oldnumberstonew = array();
|
||||
foreach ($oldquba->get_attempt_iterator() as $oldslot => $oldqa) {
|
||||
$newslot = $quba->add_question($oldqa->get_question(), $oldqa->get_max_mark());
|
||||
$newslot = $quba->add_question($oldqa->get_question(false), $oldqa->get_max_mark());
|
||||
|
||||
$quba->start_question_based_on($newslot, $oldqa);
|
||||
|
||||
|
@ -541,7 +541,7 @@ class quiz_grading_report extends quiz_default_report {
|
||||
|
||||
// Add the event we will trigger later.
|
||||
$params = [
|
||||
'objectid' => $attemptobj->get_question_attempt($assumedslotforevents)->get_question()->id,
|
||||
'objectid' => $attemptobj->get_question_attempt($assumedslotforevents)->get_question_id(),
|
||||
'courseid' => $attemptobj->get_courseid(),
|
||||
'context' => context_module::instance($attemptobj->get_cmid()),
|
||||
'other' => [
|
||||
|
@ -141,7 +141,7 @@ class quiz_first_or_all_responses_table extends quiz_last_responses_table {
|
||||
*/
|
||||
public function get_summary_after_try($tablerow, $slot) {
|
||||
$qa = $this->get_question_attempt($tablerow->usageid, $slot);
|
||||
if (!($qa->get_question() instanceof question_manually_gradable)) {
|
||||
if (!($qa->get_question(false) instanceof question_manually_gradable)) {
|
||||
// No responses, and we cannot call summarise_response below.
|
||||
return null;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ class mod_quiz_attempt_walkthrough_testcase extends advanced_testcase {
|
||||
$this->assertFalse($attemptobj->has_response_to_at_least_one_graded_question());
|
||||
|
||||
$tosubmit = array();
|
||||
$selectedquestionid = $quba->get_question_attempt(1)->get_question()->id;
|
||||
$selectedquestionid = $quba->get_question_attempt(1)->get_question_id();
|
||||
$tosubmit[1] = array('answer' => $randqanswer);
|
||||
$tosubmit[2] = array(
|
||||
'frog' => 'amphibian',
|
||||
|
@ -58,7 +58,7 @@ abstract class question_behaviour {
|
||||
*/
|
||||
public function __construct(question_attempt $qa, $preferredbehaviour) {
|
||||
$this->qa = $qa;
|
||||
$this->question = $qa->get_question();
|
||||
$this->question = $qa->get_question(false);
|
||||
if (!$this->is_compatible_question($this->question)) {
|
||||
throw new coding_exception('This behaviour (' . $this->get_name() .
|
||||
') cannot work with this question (' . get_class($this->question) . ')');
|
||||
|
@ -117,7 +117,7 @@ class qbehaviour_missing_test extends advanced_testcase {
|
||||
$this->assertEquals(array('-submit' => '1', 'choice0' => '1'), $step->get_all_data());
|
||||
|
||||
$output = $qa->render(new question_display_options(), '1');
|
||||
$this->assertRegExp('/' . preg_quote($qa->get_question()->questiontext, '/') . '/', $output);
|
||||
$this->assertRegExp('/' . preg_quote($qa->get_question(false)->questiontext, '/') . '/', $output);
|
||||
$this->assertRegExp('/' . preg_quote(
|
||||
get_string('questionusedunknownmodel', 'qbehaviour_missing'), '/') . '/', $output);
|
||||
$this->assertTag(array('tag'=>'div', 'attributes'=>array('class'=>'warning')), $output);
|
||||
|
@ -188,7 +188,8 @@ abstract class qbehaviour_renderer extends plugin_renderer_base {
|
||||
public function manual_comment_view(question_attempt $qa, question_display_options $options) {
|
||||
$output = '';
|
||||
if ($qa->has_manual_comment()) {
|
||||
$output .= get_string('commentx', 'question', $qa->get_behaviour()->format_comment(null, null, $options->context));
|
||||
$output .= get_string('commentx', 'question',
|
||||
$qa->get_behaviour(false)->format_comment(null, null, $options->context));
|
||||
}
|
||||
if ($options->manualcommentlink) {
|
||||
$url = new moodle_url($options->manualcommentlink, array('slot' => $qa->get_slot()));
|
||||
|
@ -165,7 +165,7 @@ class provider implements
|
||||
]);
|
||||
|
||||
foreach ($quba->get_attempt_iterator() as $qa) {
|
||||
$question = $qa->get_question();
|
||||
$question = $qa->get_question(false);
|
||||
$slotno = $qa->get_slot();
|
||||
$questionnocontext = array_merge($questionscontext, [$slotno]);
|
||||
|
||||
@ -197,7 +197,6 @@ class provider implements
|
||||
}
|
||||
|
||||
if ($options->manualcomment != \question_display_options::HIDDEN) {
|
||||
$behaviour = $qa->get_behaviour();
|
||||
if ($qa->has_manual_comment()) {
|
||||
// Note - the export of the step data will ensure that the files are exported.
|
||||
// No need to do it again here.
|
||||
@ -211,7 +210,7 @@ class provider implements
|
||||
$step->get_id(),
|
||||
$comment
|
||||
);
|
||||
$data->comment = $behaviour->format_comment($comment, $commentformat);
|
||||
$data->comment = $qa->get_behaviour(false)->format_comment($comment, $commentformat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +271,6 @@ class provider implements
|
||||
}
|
||||
|
||||
if ($step->has_behaviour_var('comment')) {
|
||||
$behaviour = $qa->get_behaviour();
|
||||
$comment = $step->get_behaviour_var('comment');
|
||||
$commentformat = $step->get_behaviour_var('commentformat');
|
||||
|
||||
@ -300,7 +298,7 @@ class provider implements
|
||||
$step->get_id()
|
||||
);
|
||||
|
||||
$stepdata->comment = $behaviour->format_comment($comment, $commentformat);
|
||||
$stepdata->comment = $qa->get_behaviour(false)->format_comment($comment, $commentformat);
|
||||
}
|
||||
|
||||
// Export any response files associated with this step.
|
||||
|
@ -118,7 +118,7 @@ class question_engine_data_mapper {
|
||||
$record->questionusageid = $qa->get_usage_id();
|
||||
$record->slot = $qa->get_slot();
|
||||
$record->behaviour = $qa->get_behaviour_name();
|
||||
$record->questionid = $qa->get_question()->id;
|
||||
$record->questionid = $qa->get_question_id();
|
||||
$record->variant = $qa->get_variant();
|
||||
$record->maxmark = $qa->get_max_mark();
|
||||
$record->minfraction = $qa->get_min_fraction();
|
||||
|
@ -696,7 +696,7 @@ abstract class question_flags {
|
||||
public static function get_postdata(question_attempt $qa) {
|
||||
$qaid = $qa->get_database_id();
|
||||
$qubaid = $qa->get_usage_id();
|
||||
$qid = $qa->get_question()->id;
|
||||
$qid = $qa->get_question_id();
|
||||
$slot = $qa->get_slot();
|
||||
$checksum = self::get_toggle_checksum($qubaid, $qid, $qaid, $slot);
|
||||
return "qaid={$qaid}&qubaid={$qubaid}&qid={$qid}&slot={$slot}&checksum={$checksum}&sesskey=" .
|
||||
|
@ -68,19 +68,32 @@ class question_attempt {
|
||||
|
||||
/**
|
||||
* @var string means first try at a question during an attempt by a user.
|
||||
* Constant used when calling classify response.
|
||||
*/
|
||||
const FIRST_TRY = 'firsttry';
|
||||
|
||||
/**
|
||||
* @var string means last try at a question during an attempt by a user.
|
||||
* Constant used when calling classify response.
|
||||
*/
|
||||
const LAST_TRY = 'lasttry';
|
||||
|
||||
/**
|
||||
* @var string means all tries at a question during an attempt by a user.
|
||||
* Constant used when calling classify response.
|
||||
*/
|
||||
const ALL_TRIES = 'alltries';
|
||||
|
||||
/**
|
||||
* @var bool used to manage the lazy-initialisation of question objects.
|
||||
*/
|
||||
const QUESTION_STATE_NOT_APPLIED = false;
|
||||
|
||||
/**
|
||||
* @var bool used to manage the lazy-initialisation of question objects.
|
||||
*/
|
||||
const QUESTION_STATE_APPLIED = true;
|
||||
|
||||
/** @var integer if this attempts is stored in the question_attempts table, the id of that row. */
|
||||
protected $id = null;
|
||||
|
||||
@ -99,6 +112,12 @@ class question_attempt {
|
||||
/** @var question_definition the question this is an attempt at. */
|
||||
protected $question;
|
||||
|
||||
/**
|
||||
* @var bool tracks whether $question has had {@link question_definition::start_attempt()} or
|
||||
* {@link question_definition::apply_attempt_state()} called.
|
||||
*/
|
||||
protected $questioninitialised;
|
||||
|
||||
/** @var int which variant of the question to use. */
|
||||
protected $variant;
|
||||
|
||||
@ -184,6 +203,7 @@ class question_attempt {
|
||||
public function __construct(question_definition $question, $usageid,
|
||||
question_usage_observer $observer = null, $maxmark = null) {
|
||||
$this->question = $question;
|
||||
$this->questioninitialised = self::QUESTION_STATE_NOT_APPLIED;
|
||||
$this->usageid = $usageid;
|
||||
if (is_null($observer)) {
|
||||
$observer = new question_usage_null_observer();
|
||||
@ -205,11 +225,29 @@ class question_attempt {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return question_definition the question this is an attempt at. */
|
||||
public function get_question() {
|
||||
/**
|
||||
* Get the question that is being attempted.
|
||||
*
|
||||
* @param bool $requirequestioninitialised set this to false if you don't need
|
||||
* the behaviour initialised, which may improve performance.
|
||||
* @return question_definition the question this is an attempt at.
|
||||
*/
|
||||
public function get_question($requirequestioninitialised = true) {
|
||||
if ($requirequestioninitialised && !empty($this->steps)) {
|
||||
$this->ensure_question_initialised();
|
||||
}
|
||||
return $this->question;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the question being attempted.
|
||||
*
|
||||
* @return int question id.
|
||||
*/
|
||||
public function get_question_id() {
|
||||
return $this->question->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variant of the question being used in a given slot.
|
||||
* @return int the variant number.
|
||||
@ -279,9 +317,15 @@ class question_attempt {
|
||||
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @param bool $requirequestioninitialised set this to false if you don't need
|
||||
* the behaviour initialised, which may improve performance.
|
||||
* @return question_behaviour the behaviour that is controlling this attempt.
|
||||
*/
|
||||
public function get_behaviour() {
|
||||
public function get_behaviour($requirequestioninitialised = true) {
|
||||
if ($requirequestioninitialised && !empty($this->steps)) {
|
||||
$this->ensure_question_initialised();
|
||||
}
|
||||
return $this->behaviour;
|
||||
}
|
||||
|
||||
@ -769,10 +813,11 @@ class question_attempt {
|
||||
|
||||
/**
|
||||
* Produce a plain-text summary of what the user did during a step.
|
||||
* @param question_attempt_step $step the step in quetsion.
|
||||
* @param question_attempt_step $step the step in question.
|
||||
* @return string a summary of what was done during that step.
|
||||
*/
|
||||
public function summarise_action(question_attempt_step $step) {
|
||||
$this->ensure_question_initialised();
|
||||
return $this->behaviour->summarise_action($step);
|
||||
}
|
||||
|
||||
@ -852,6 +897,7 @@ class question_attempt {
|
||||
* @return string HTML fragment representing the question.
|
||||
*/
|
||||
public function render($options, $number, $page = null) {
|
||||
$this->ensure_question_initialised();
|
||||
if (is_null($page)) {
|
||||
global $PAGE;
|
||||
$page = $PAGE;
|
||||
@ -867,6 +913,7 @@ class question_attempt {
|
||||
* @return string HTML fragment.
|
||||
*/
|
||||
public function render_head_html($page = null) {
|
||||
$this->ensure_question_initialised();
|
||||
if (is_null($page)) {
|
||||
global $PAGE;
|
||||
$page = $PAGE;
|
||||
@ -889,6 +936,7 @@ class question_attempt {
|
||||
* @return string HTML fragment representing the question.
|
||||
*/
|
||||
public function render_at_step($seq, $options, $number, $preferredbehaviour) {
|
||||
$this->ensure_question_initialised();
|
||||
$restrictedqa = new question_attempt_with_restricted_history($this, $seq, $preferredbehaviour);
|
||||
return $restrictedqa->render($options, $number);
|
||||
}
|
||||
@ -903,6 +951,7 @@ class question_attempt {
|
||||
* @return bool true if the user can access this file.
|
||||
*/
|
||||
public function check_file_access($options, $component, $filearea, $args, $forcedownload) {
|
||||
$this->ensure_question_initialised();
|
||||
return $this->behaviour->check_file_access($options, $component, $filearea, $args, $forcedownload);
|
||||
}
|
||||
|
||||
@ -976,7 +1025,7 @@ class question_attempt {
|
||||
* {@link question_usage_by_activity::start_question()} instead.
|
||||
*
|
||||
* @param string|question_behaviour $preferredbehaviour the name of the
|
||||
* desired archetypal behaviour, or an actual model instance.
|
||||
* desired archetypal behaviour, or an actual behaviour 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.
|
||||
@ -1014,6 +1063,7 @@ class question_attempt {
|
||||
} else {
|
||||
$this->behaviour->init_first_step($firststep, $variant);
|
||||
}
|
||||
$this->questioninitialised = self::QUESTION_STATE_APPLIED;
|
||||
$this->add_step($firststep);
|
||||
|
||||
// Record questionline and correct answer.
|
||||
@ -1041,6 +1091,7 @@ class question_attempt {
|
||||
* @return array name => value pairs.
|
||||
*/
|
||||
protected function get_resume_data() {
|
||||
$this->ensure_question_initialised();
|
||||
$resumedata = $this->behaviour->get_resume_data();
|
||||
foreach ($resumedata as $name => $value) {
|
||||
if ($value instanceof question_file_loader) {
|
||||
@ -1195,6 +1246,8 @@ class question_attempt {
|
||||
* @return array name => value pairs that could be passed to {@link process_action()}.
|
||||
*/
|
||||
public function get_submitted_data($postdata = null) {
|
||||
$this->ensure_question_initialised();
|
||||
|
||||
$submitteddata = $this->get_expected_data(
|
||||
$this->behaviour->get_expected_data(), $postdata, '-');
|
||||
|
||||
@ -1233,6 +1286,7 @@ class question_attempt {
|
||||
* @return array|null name => value pairs that could be passed to {@link process_action()}.
|
||||
*/
|
||||
public function get_correct_response() {
|
||||
$this->ensure_question_initialised();
|
||||
$response = $this->question->get_correct_response();
|
||||
if (is_null($response)) {
|
||||
return null;
|
||||
@ -1283,6 +1337,7 @@ class question_attempt {
|
||||
* @return boolean whether this attempt can finish naturally.
|
||||
*/
|
||||
public function can_finish_during_attempt() {
|
||||
$this->ensure_question_initialised();
|
||||
return $this->behaviour->can_finish_during_attempt();
|
||||
}
|
||||
|
||||
@ -1294,6 +1349,7 @@ class question_attempt {
|
||||
* @param int $existingstepid used by the regrade code.
|
||||
*/
|
||||
public function process_action($submitteddata, $timestamp = null, $userid = null, $existingstepid = null) {
|
||||
$this->ensure_question_initialised();
|
||||
$pendingstep = new question_attempt_pending_step($submitteddata, $timestamp, $userid, $existingstepid);
|
||||
$this->discard_autosaved_step();
|
||||
if ($this->behaviour->process_action($pendingstep) == self::KEEP) {
|
||||
@ -1315,6 +1371,7 @@ class question_attempt {
|
||||
* @return bool whether anything was saved.
|
||||
*/
|
||||
public function process_autosave($submitteddata, $timestamp = null, $userid = null) {
|
||||
$this->ensure_question_initialised();
|
||||
$pendingstep = new question_attempt_pending_step($submitteddata, $timestamp, $userid);
|
||||
if ($this->behaviour->process_autosave($pendingstep) == self::KEEP) {
|
||||
$this->add_autosaved_step($pendingstep);
|
||||
@ -1333,6 +1390,7 @@ class question_attempt {
|
||||
* @param int $userid the user to attribute the aciton to. (If not given, use the current user.)
|
||||
*/
|
||||
public function finish($timestamp = null, $userid = null) {
|
||||
$this->ensure_question_initialised();
|
||||
$this->convert_autosaved_step_to_real_step();
|
||||
$this->process_action(array('-finish' => 1), $timestamp, $userid);
|
||||
}
|
||||
@ -1345,6 +1403,7 @@ class question_attempt {
|
||||
* after the regrade, or whether it may still be in progress (default false).
|
||||
*/
|
||||
public function regrade(question_attempt $oldqa, $finished) {
|
||||
$oldqa->ensure_question_initialised();
|
||||
$first = true;
|
||||
foreach ($oldqa->get_step_iterator() as $step) {
|
||||
$this->observer->notify_step_deleted($step, $this);
|
||||
@ -1404,6 +1463,7 @@ class question_attempt {
|
||||
* @param int $userid the user to attribute the aciton to. (If not given, use the current user.)
|
||||
*/
|
||||
public function manual_grade($comment, $mark, $commentformat = null, $timestamp = null, $userid = null) {
|
||||
$this->ensure_question_initialised();
|
||||
$submitteddata = array('-comment' => $comment);
|
||||
if (is_null($commentformat)) {
|
||||
debugging('You should pass $commentformat to manual_grade.', DEBUG_DEVELOPER);
|
||||
@ -1476,6 +1536,7 @@ class question_attempt {
|
||||
* and the second key is subpartid.
|
||||
*/
|
||||
public function classify_response($whichtries = self::LAST_TRY) {
|
||||
$this->ensure_question_initialised();
|
||||
return $this->behaviour->classify_response($whichtries);
|
||||
}
|
||||
|
||||
@ -1541,7 +1602,8 @@ class question_attempt {
|
||||
$autosavedsequencenumber = null;
|
||||
while ($record && $record->questionattemptid == $questionattemptid && !is_null($record->attemptstepid)) {
|
||||
$sequencenumber = $record->sequencenumber;
|
||||
$nextstep = question_attempt_step::load_from_records($records, $record->attemptstepid, $qa->get_question()->get_type_name());
|
||||
$nextstep = question_attempt_step::load_from_records($records, $record->attemptstepid,
|
||||
$qa->get_question(false)->get_type_name());
|
||||
|
||||
if ($sequencenumber < 0) {
|
||||
if (!$autosavedstep) {
|
||||
@ -1553,9 +1615,6 @@ class question_attempt {
|
||||
}
|
||||
} else {
|
||||
$qa->steps[$i] = $nextstep;
|
||||
if ($i == 0) {
|
||||
$question->apply_attempt_state($qa->steps[0]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
@ -1578,6 +1637,26 @@ class question_attempt {
|
||||
return $qa;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is part of the lazy-initialisation of question objects.
|
||||
*
|
||||
* Methods which require $this->question to be fully initialised
|
||||
* (to have had init_first_step or apply_attempt_state called on it)
|
||||
* should call this method before proceeding.
|
||||
*/
|
||||
protected function ensure_question_initialised() {
|
||||
if ($this->questioninitialised === self::QUESTION_STATE_APPLIED) {
|
||||
return; // Already done.
|
||||
}
|
||||
|
||||
if (empty($this->steps)) {
|
||||
throw new coding_exception('You must call start() before doing anything to a question_attempt().');
|
||||
}
|
||||
|
||||
$this->question->apply_attempt_state($this->steps[0]);
|
||||
$this->questioninitialised = self::QUESTION_STATE_APPLIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow access to steps with responses submitted by students for grading in a question attempt.
|
||||
*
|
||||
|
@ -69,7 +69,7 @@ class question_usage_by_activity {
|
||||
/** @var string plugin name of the plugin this usage belongs to. */
|
||||
protected $owningcomponent;
|
||||
|
||||
/** @var array {@link question_attempt}s that make up this usage. */
|
||||
/** @var question_attempt[] {@link question_attempt}s that make up this usage. */
|
||||
protected $questionattempts = array();
|
||||
|
||||
/** @var question_usage_observer that tracks changes to this usage. */
|
||||
@ -218,10 +218,12 @@ class question_usage_by_activity {
|
||||
/**
|
||||
* Get the question_definition for a question in this attempt.
|
||||
* @param int $slot the number used to identify this question within this usage.
|
||||
* @param bool $requirequestioninitialised set this to false if you don't need
|
||||
* the behaviour initialised, which may improve performance.
|
||||
* @return question_definition the requested question object.
|
||||
*/
|
||||
public function get_question($slot) {
|
||||
return $this->get_question_attempt($slot)->get_question();
|
||||
public function get_question($slot, $requirequestioninitialised = true) {
|
||||
return $this->get_question_attempt($slot)->get_question($requirequestioninitialised);
|
||||
}
|
||||
|
||||
/** @return array all the identifying numbers of all the questions in this usage. */
|
||||
@ -887,7 +889,7 @@ class question_usage_by_activity {
|
||||
$newmaxmark = $oldqa->get_max_mark();
|
||||
}
|
||||
|
||||
$newqa = new question_attempt($oldqa->get_question(), $oldqa->get_usage_id(),
|
||||
$newqa = new question_attempt($oldqa->get_question(false), $oldqa->get_usage_id(),
|
||||
$this->observer, $newmaxmark);
|
||||
$newqa->set_database_id($oldqa->get_database_id());
|
||||
$newqa->set_slot($oldqa->get_slot());
|
||||
|
@ -92,7 +92,7 @@ class core_question_renderer extends plugin_renderer_base {
|
||||
'id' => $qa->get_outer_question_div_unique_id(),
|
||||
'class' => implode(' ', array(
|
||||
'que',
|
||||
$qa->get_question()->qtype->name(),
|
||||
$qa->get_question(false)->get_type_name(),
|
||||
$qa->get_behaviour_name(),
|
||||
$qa->get_state_class($options->correctness && $qa->has_marks()),
|
||||
))
|
||||
@ -355,7 +355,7 @@ class core_question_renderer extends plugin_renderer_base {
|
||||
if ($params['returnurl'] instanceof moodle_url) {
|
||||
$params['returnurl'] = $params['returnurl']->out_as_local_url(false);
|
||||
}
|
||||
$params['id'] = $qa->get_question()->id;
|
||||
$params['id'] = $qa->get_question_id();
|
||||
$editurl = new moodle_url('/question/question.php', $params);
|
||||
|
||||
return html_writer::tag('div', html_writer::link(
|
||||
|
@ -66,7 +66,7 @@ class question_attempt_db_test extends data_loading_method_test_base {
|
||||
$qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
|
||||
question_bank::end_unit_test();
|
||||
|
||||
$this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
|
||||
$this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
|
||||
|
||||
$this->assertEquals(6, $qa->get_num_steps());
|
||||
|
||||
@ -129,7 +129,7 @@ class question_attempt_db_test extends data_loading_method_test_base {
|
||||
question_bank::end_unit_test();
|
||||
|
||||
$missingq = question_bank::get_qtype('missingtype')->make_deleted_instance(-1, 2);
|
||||
$this->assertEquals($missingq, $qa->get_question());
|
||||
$this->assertEquals($missingq, $qa->get_question(false));
|
||||
|
||||
$this->assertEquals(1, $qa->get_num_steps());
|
||||
|
||||
@ -162,7 +162,7 @@ class question_attempt_db_test extends data_loading_method_test_base {
|
||||
$qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
|
||||
question_bank::end_unit_test();
|
||||
|
||||
$this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
|
||||
$this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
|
||||
|
||||
$this->assertEquals(4, $qa->get_num_steps());
|
||||
$this->assertTrue($qa->has_autosaved_step());
|
||||
@ -224,7 +224,7 @@ class question_attempt_db_test extends data_loading_method_test_base {
|
||||
$qa = question_attempt::load_from_records($records, 1, $observer, 'deferredfeedback');
|
||||
question_bank::end_unit_test();
|
||||
|
||||
$this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
|
||||
$this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
|
||||
|
||||
$this->assertEquals(3, $qa->get_num_steps());
|
||||
$this->assertFalse($qa->has_autosaved_step());
|
||||
|
@ -65,7 +65,7 @@ class question_attempt_testcase extends advanced_testcase {
|
||||
|
||||
public function test_constructor_sets_maxmark() {
|
||||
$qa = new question_attempt($this->question, $this->usageid);
|
||||
$this->assertSame($this->question, $qa->get_question());
|
||||
$this->assertSame($this->question, $qa->get_question(false));
|
||||
$this->assertEquals(3, $qa->get_max_mark());
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ class question_usage_db_test extends data_loading_method_test_base {
|
||||
|
||||
$qa = $quba->get_question_attempt(1);
|
||||
|
||||
$this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
|
||||
$this->assertEquals($question->questiontext, $qa->get_question(false)->questiontext);
|
||||
|
||||
$this->assertEquals(3, $qa->get_num_steps());
|
||||
|
||||
|
@ -92,10 +92,10 @@ class question_usage_by_activity_test extends advanced_testcase {
|
||||
$slot = $quba->add_question($tf);
|
||||
|
||||
// Exercise SUT and verify.
|
||||
$this->assertSame($tf, $quba->get_question($slot));
|
||||
$this->assertSame($tf, $quba->get_question($slot, false));
|
||||
|
||||
$this->expectException('moodle_exception');
|
||||
$quba->get_question($slot + 1);
|
||||
$quba->get_question($slot + 1, false);
|
||||
}
|
||||
|
||||
public function test_extract_responses() {
|
||||
|
@ -173,7 +173,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
|
||||
public function test_regrade_same_steps() {
|
||||
|
||||
// Change the question in a minor way and regrade.
|
||||
$this->quba->get_question($this->slot)->answers[14]->fraction = 0.5;
|
||||
$this->quba->get_question($this->slot, false)->answers[14]->fraction = 0.5;
|
||||
$this->quba->regrade_all_questions();
|
||||
|
||||
// Here, the qa, and all the steps, should be marked as updated.
|
||||
@ -205,7 +205,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
|
||||
// Change the question so that 'toad' is also right, and regrade. This
|
||||
// will mean that the try again, and second try states are no longer
|
||||
// needed, so they should be dropped.
|
||||
$this->quba->get_question($this->slot)->answers[14]->fraction = 1;
|
||||
$this->quba->get_question($this->slot, false)->answers[14]->fraction = 1;
|
||||
$this->quba->regrade_all_questions();
|
||||
|
||||
$this->assertEquals(0, count($this->observer->get_attempts_added()));
|
||||
@ -253,7 +253,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
|
||||
$this->quba->process_action($this->slot, array('answer' => 'frog', '-submit' => 1));
|
||||
$this->quba->finish_all_questions();
|
||||
|
||||
$this->quba->get_question($this->slot)->answers[14]->fraction = 1;
|
||||
$this->quba->get_question($this->slot, false)->answers[14]->fraction = 1;
|
||||
$this->quba->regrade_all_questions();
|
||||
|
||||
$this->assertEquals(0, count($this->observer->get_attempts_added()));
|
||||
|
@ -1,5 +1,33 @@
|
||||
This files describes API changes for the core question engine.
|
||||
|
||||
=== 3.9 ===
|
||||
|
||||
1) In the past, whenever a question_usage_by_activity was loaded from the database,
|
||||
the apply_attempt_state was immediately called on every question, whether the
|
||||
results of doing that were ever used, or not.
|
||||
|
||||
Now we have changed the code flow, so that apply_attempt_state is only called
|
||||
when some data or processing is requested (e.g. analysing a response or rendering
|
||||
the question) which requires the question to be fully initialised. This is MDL-67183.
|
||||
|
||||
This change should be completely invisible with everything handled by the question
|
||||
engine. If you don't change your code, it should continue to work.
|
||||
|
||||
However, to get the full advantage of this change, you should review your code,
|
||||
and look at every call to get_question or get_behaviour (on a question_attempt or
|
||||
question_usage_by_activity). The problem with these methods is that the question engine
|
||||
cannot know what you are planning to do with the question once you have got it.
|
||||
Therefore, they have to assume that apply_attempt_state must be called - which can be expensive.
|
||||
If you know that you don't need that (because, for example, you are just going to
|
||||
look at ->id or ->questiontext or something simple) then you should pass
|
||||
false to these functions, to get the possible performance benefit.
|
||||
In addition, there is a new method $qa->get_question_id() to handle that case more simply.
|
||||
|
||||
Note that you don't have worry about this in places like the renderer for your question
|
||||
type, because by the time you are in the renderer, the question will already have been
|
||||
initialised.
|
||||
|
||||
|
||||
=== 3.7 ===
|
||||
|
||||
1) When a question is rendered, the outer div of the question has an id="q123"
|
||||
|
@ -95,7 +95,7 @@ if ($previewid) {
|
||||
}
|
||||
|
||||
$slot = $quba->get_first_question_number();
|
||||
$usedquestion = $quba->get_question($slot);
|
||||
$usedquestion = $quba->get_question($slot, false);
|
||||
if ($usedquestion->id != $question->id) {
|
||||
print_error('questionidmismatch', 'question');
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ function question_preview_question_pluginfile($course, $context, $component,
|
||||
|
||||
$quba = question_engine::load_questions_usage_by_activity($qubaid);
|
||||
|
||||
if (!question_has_capability_on($quba->get_question($slot), 'use')) {
|
||||
if (!question_has_capability_on($quba->get_question($slot, false), 'use')) {
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ trait core_question_privacy_helper {
|
||||
$data
|
||||
) {
|
||||
$attempt = $quba->get_question_attempt($slotno);
|
||||
$question = $attempt->get_question();
|
||||
$question = $attempt->get_question(false);
|
||||
|
||||
// Check the question data exported.
|
||||
$this->assertEquals($data->name, $question->name);
|
||||
|
@ -46,7 +46,7 @@ class qtype_ddmarker_question extends qtype_ddtoimage_question_base {
|
||||
$validfilearea = false;
|
||||
}
|
||||
if ($component == 'qtype_ddmarker' && $validfilearea) {
|
||||
$question = $qa->get_question();
|
||||
$question = $qa->get_question(false);
|
||||
$itemid = reset($args);
|
||||
return $itemid == $question->id;
|
||||
} else {
|
||||
|
@ -110,7 +110,7 @@ class qtype_missing_test extends question_testcase {
|
||||
$output = $qa->render(new question_display_options(), '1');
|
||||
|
||||
$this->assertRegExp('/' .
|
||||
preg_quote($qa->get_question()->questiontext, '/') . '/', $output);
|
||||
preg_quote($qa->get_question(false)->questiontext, '/') . '/', $output);
|
||||
$this->assertRegExp('/' .
|
||||
preg_quote(get_string('missingqtypewarning', 'qtype_missingtype'), '/') . '/', $output);
|
||||
$this->assert(new question_contains_tag_with_attribute(
|
||||
|
Loading…
x
Reference in New Issue
Block a user