function question_process_responses in Quiz 6.6
Same name and namespace in other branches
- 6.5 includes/moodle/lib/questionlib.php \question_process_responses()
Processes an array of student responses, grading and saving them as appropriate
Parameters
object $question Full question object, passed by reference:
object $state Full state object, passed by reference:
object $action object with the fields ->responses which: is an array holding the student responses, ->action which specifies the action, e.g., QUESTION_EVENTGRADE, and ->timestamp which is a timestamp from when the responses were submitted by the student.
object $cmoptions:
object $attempt The attempt is passed by reference so that: during grading its ->sumgrades field can be updated
Return value
boolean Indicates success/failure
2 calls to question_process_responses()
- get_question_states in includes/
moodle/ lib/ questionlib.php - Loads the most recent state of each question session from the database or create new one.
- regrade_question_in_attempt in includes/
moodle/ lib/ questionlib.php - For a given question in an attempt we walk the complete history of states and recalculate the grades as we go along.
File
- includes/
moodle/ lib/ questionlib.php, line 1288
Code
function question_process_responses(&$question, &$state, $action, $cmoptions, &$attempt) {
global $QTYPES;
// if no responses are set initialise to empty response
if (!isset($action->responses)) {
$action->responses = array(
'' => '',
);
}
// make sure these are gone!
unset($action->responses['submit'], $action->responses['validate']);
// Check the question session is still open
if (question_state_is_closed($state)) {
return true;
}
// If $action->event is not set that implies saving
if (!isset($action->event)) {
debugging('Ambiguous action in question_process_responses.', DEBUG_DEVELOPER);
$action->event = QUESTION_EVENTSAVE;
}
// If submitted then compare against last graded
// responses, not last given responses in this case
if (question_isgradingevent($action->event)) {
$state->responses = $state->last_graded->responses;
}
// Check for unchanged responses (exactly unchanged, not equivalent).
// We also have to catch questions that the student has not yet attempted
$sameresponses = $QTYPES[$question->qtype]
->compare_responses($question, $action, $state);
if (!empty($state->last_graded) && $state->last_graded->event == QUESTION_EVENTOPEN && question_isgradingevent($action->event)) {
$sameresponses = false;
}
// If the response has not been changed then we do not have to process it again
// unless the attempt is closing or validation is requested
if ($sameresponses and QUESTION_EVENTCLOSE != $action->event and QUESTION_EVENTVALIDATE != $action->event) {
return true;
}
// Roll back grading information to last graded state and set the new
// responses
$newstate = clone $state->last_graded;
$newstate->responses = $action->responses;
$newstate->seq_number = $state->seq_number + 1;
$newstate->changed = true;
// will assure that it gets saved to the database
$newstate->last_graded = clone $state->last_graded;
$newstate->timestamp = $action->timestamp;
$state = $newstate;
// Set the event to the action we will perform. The question type specific
// grading code may override this by setting it to QUESTION_EVENTCLOSE if the
// attempt at the question causes the session to close
$state->event = $action->event;
if (!question_isgradingevent($action->event)) {
// Grade the response but don't update the overall grade
if (!$QTYPES[$question->qtype]
->grade_responses($question, $state, $cmoptions)) {
return false;
}
// Temporary hack because question types are not given enough control over what is going
// on. Used by Opaque questions.
// TODO fix this code properly.
if (!empty($state->believeevent)) {
// If the state was graded we need to ...
if (question_state_is_graded($state)) {
question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
// update the attempt grade
$attempt->sumgrades -= (double) $state->last_graded->grade;
$attempt->sumgrades += (double) $state->grade;
// and update the last_graded field.
unset($state->last_graded);
$state->last_graded = clone $state;
unset($state->last_graded->changed);
}
}
else {
// Don't allow the processing to change the event type
$state->event = $action->event;
}
}
else {
// grading event
// Unless the attempt is closing, we want to work out if the current responses
// (or equivalent responses) were already given in the last graded attempt.
if (QUESTION_EVENTCLOSE != $action->event && QUESTION_EVENTOPEN != $state->last_graded->event && $QTYPES[$question->qtype]
->compare_responses($question, $state, $state->last_graded)) {
$state->event = QUESTION_EVENTDUPLICATE;
}
// If we did not find a duplicate or if the attempt is closing, perform grading
if (!$sameresponses and QUESTION_EVENTDUPLICATE != $state->event or QUESTION_EVENTCLOSE == $action->event) {
if (!$QTYPES[$question->qtype]
->grade_responses($question, $state, $cmoptions)) {
return false;
}
// Calculate overall grade using correct penalty method
question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions);
}
// If the state was graded we need to ...
if (question_state_is_graded($state)) {
// update the attempt grade
$attempt->sumgrades -= (double) $state->last_graded->grade;
$attempt->sumgrades += (double) $state->grade;
// and update the last_graded field.
unset($state->last_graded);
$state->last_graded = clone $state;
unset($state->last_graded->changed);
}
}
$attempt->timemodified = $action->timestamp;
return true;
}