Exemple #1
0
 function test_question_state_is_closed()
 {
     $state = new stdClass();
     $state->event = QUESTION_EVENTOPEN;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTNAVIGATE;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTSAVE;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTGRADE;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTDUPLICATE;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTVALIDATE;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTSUBMIT;
     $this->assertFalse(question_state_is_closed($state));
     $state->event = QUESTION_EVENTCLOSEANDGRADE;
     $this->assertTrue(question_state_is_closed($state));
     $state->event = QUESTION_EVENTCLOSE;
     $this->assertTrue(question_state_is_closed($state));
     $state->event = QUESTION_EVENTMANUALGRADE;
     $this->assertTrue(question_state_is_closed($state));
 }
Exemple #2
0
/**
 * Determine render options
 *
 * @param int $reviewoptions
 * @param object $state
 */
function quiz_get_renderoptions($reviewoptions, $state)
{
    $options = new stdClass();
    // Show the question in readonly (review) mode if the question is in
    // the closed state
    $options->readonly = question_state_is_closed($state);
    // Show feedback once the question has been graded (if allowed by the quiz)
    $options->feedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show validation only after a validation event
    $options->validation = QUESTION_EVENTVALIDATE === $state->event;
    // Show correct responses in readonly mode if the quiz allows it
    $options->correct_responses = $options->readonly && $reviewoptions & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_IMMEDIATELY;
    // Show general feedback if the question has been graded and the quiz allows it.
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_GENERALFEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show overallfeedback once the attempt is over.
    $options->overallfeedback = false;
    // Always show responses and scores
    $options->responses = true;
    $options->scores = true;
    $options->quizstate = QUIZ_STATE_DURING;
    return $options;
}
Exemple #3
0
/**
* Processes an array of student responses, grading and saving them as appropriate
*
* @param object $question Full question object, passed by reference
* @param object $state    Full state object, passed by reference
* @param 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.
* @param object $cmoptions
* @param object $attempt  The attempt is passed by reference so that
*                         during grading its ->sumgrades field can be updated
* @return boolean         Indicates success/failure
*/
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;
}
Exemple #4
0
/**
 * Determine render options
 *
 * @param int $reviewoptions
 * @param object $state
 */
function quiz_get_renderoptions($quiz, $attempt, $context, $state)
{
    $reviewoptions = $quiz->review;
    $options = new stdClass();
    $options->flags = quiz_get_flag_option($attempt, $context);
    // Show the question in readonly (review) mode if the question is in
    // the closed state
    $options->readonly = question_state_is_closed($state);
    // Show feedback once the question has been graded (if allowed by the quiz)
    $options->feedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show correct responses in readonly mode if the quiz allows it
    $options->correct_responses = $options->readonly && $reviewoptions & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_IMMEDIATELY;
    // Show general feedback if the question has been graded and the quiz allows it.
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & QUIZ_REVIEW_GENERALFEEDBACK & QUIZ_REVIEW_IMMEDIATELY;
    // Show overallfeedback once the attempt is over.
    $options->overallfeedback = false;
    // Always show responses and scores
    $options->responses = true;
    $options->scores = true;
    $options->quizstate = QUIZ_STATE_DURING;
    $options->history = false;
    return $options;
}
 /**
  * @param string $colname the name of the column.
  * @param object $attempt the row of data - see the SQL in display() in
  * mod/quiz/report/overview/report.php to see what fields are present,
  * and what they are called.
  * @return string the contents of the cell.
  */
 function other_cols($colname, $attempt)
 {
     global $OUTPUT;
     if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)) {
         $questionid = $matches[1];
         $question = $this->questions[$questionid];
         if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])) {
             $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
         } else {
             $stateforqinattempt = false;
         }
         if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) {
             $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question');
             if (!$this->is_downloading()) {
                 if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])) {
                     $gradefromdb = $grade;
                     $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question');
                     $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question');
                     $grade = '<del>' . $oldgrade . '</del><br />' . $newgrade;
                 }
                 $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}");
                 $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650));
                 $linktopopup = $OUTPUT->action_link($link, $grade, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname)));
                 if ($this->questions[$questionid]->maxgrade != 0) {
                     $fractionofgrade = $stateforqinattempt->grade / $this->questions[$questionid]->maxgrade;
                     $qclass = question_get_feedback_class($fractionofgrade);
                     $feedbackimg = question_get_feedback_image($fractionofgrade);
                     $questionclass = "que";
                     return "<span class=\"{$questionclass}\"><span class=\"{$qclass}\">" . $linktopopup . "</span></span>{$feedbackimg}";
                 } else {
                     return $linktopopup;
                 }
             } else {
                 return $grade;
             }
         } else {
             if ($stateforqinattempt && question_state_is_closed($stateforqinattempt)) {
                 $text = get_string('requiresgrading', 'quiz_overview');
                 if (!$this->is_downloading()) {
                     $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt={$attempt->attempt}&question={$question->id}");
                     $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650));
                     return $OUTPUT->action_link($link, $text, $action, array('title' => get_string('reviewresponsetoq', 'quiz', $question->formattedname)));
                 } else {
                     return $text;
                 }
             } else {
                 return '--';
             }
         }
     } else {
         return NULL;
     }
 }
Exemple #6
0
function reader_get_renderoptions($reviewoptions, $state)
{
    $options = new stdClass();
    $options->readonly = question_state_is_closed($state);
    $options->feedback = question_state_is_graded($state) && $reviewoptions & READER_REVIEW_FEEDBACK & READER_REVIEW_IMMEDIATELY;
    $options->validation = QUESTION_EVENTVALIDATE === $state->event;
    $options->correct_responses = $options->readonly && $reviewoptions & READER_REVIEW_ANSWERS & READER_REVIEW_IMMEDIATELY;
    $options->generalfeedback = question_state_is_graded($state) && $reviewoptions & READER_REVIEW_GENERALFEEDBACK & READER_REVIEW_IMMEDIATELY;
    $options->overallfeedback = false;
    $options->responses = true;
    $options->scores = true;
    $options->readerstate = READER_STATE_DURING;
    return $options;
}