You are here

function get_question_states in Quiz 6.6

Same name and namespace in other branches
  1. 6.5 includes/moodle/lib/questionlib.php \get_question_states()

Loads the most recent state of each question session from the database or create new one.

For each question the most recent session state for the current attempt is loaded from the question_states table and the question type specific data and responses are added by calling {@link restore_question_state()} which in turn calls {@link restore_session_and_responses()} for each question. If no states exist for the question instance an empty state object is created representing the start of a session and empty question type specific information and responses are created by calling {@link create_session_and_responses()}.

Parameters

array $questions The questions for which sessions are to be restored or: created.

object $cmoptions:

object $attempt The attempt for which the question sessions are: to be restored or created.

mixed either the id of a previous attempt, if this attmpt is: building on a previous one, or false for a clean attempt.

Return value

array An array of state objects representing the most recent states of the question sessions.

File

includes/moodle/lib/questionlib.php, line 816

Code

function get_question_states(&$questions, $cmoptions, $attempt, $lastattemptid = false) {
  global $CFG, $QTYPES;

  // get the question ids
  $ids = array_keys($questions);
  $questionlist = implode(',', $ids);

  // The question field must be listed first so that it is used as the
  // array index in the array returned by get_records_sql
  $statefields = 'n.questionid as question, s.*, n.sumpenalty, n.manualcomment';

  // Load the newest states for the questions
  $sql = "SELECT {$statefields}" . "  FROM {$CFG->prefix}question_states s," . "       {$CFG->prefix}question_sessions n" . " WHERE s.id = n.newest" . "   AND n.attemptid = '{$attempt->uniqueid}'" . "   AND n.questionid IN ({$questionlist})";
  $states = get_records_sql($sql);

  // Load the newest graded states for the questions
  $sql = "SELECT {$statefields}" . "  FROM {$CFG->prefix}question_states s," . "       {$CFG->prefix}question_sessions n" . " WHERE s.id = n.newgraded" . "   AND n.attemptid = '{$attempt->uniqueid}'" . "   AND n.questionid IN ({$questionlist})";
  $gradedstates = get_records_sql($sql);

  // loop through all questions and set the last_graded states
  foreach ($ids as $i) {
    if (isset($states[$i])) {
      restore_question_state($questions[$i], $states[$i]);
      if (isset($gradedstates[$i])) {
        restore_question_state($questions[$i], $gradedstates[$i]);
        $states[$i]->last_graded = $gradedstates[$i];
      }
      else {
        $states[$i]->last_graded = clone $states[$i];
      }
    }
    else {
      if ($lastattemptid) {

        // If the new attempt is to be based on this previous attempt.
        // Find the responses from the previous attempt and save them to the new session
        // Load the last graded state for the question
        $statefields = 'n.questionid as question, s.*, n.sumpenalty';
        $sql = "SELECT {$statefields}" . "  FROM {$CFG->prefix}question_states s," . "       {$CFG->prefix}question_sessions n" . " WHERE s.id = n.newgraded" . "   AND n.attemptid = '{$lastattemptid}'" . "   AND n.questionid = '{$i}'";
        if (!($laststate = get_record_sql($sql))) {

          // Only restore previous responses that have been graded
          continue;
        }

        // Restore the state so that the responses will be restored
        restore_question_state($questions[$i], $laststate);
        $states[$i] = clone $laststate;
        unset($states[$i]->id);
      }
      else {

        // create a new empty state
        $states[$i] = new object();
        $states[$i]->question = $i;
        $states[$i]->responses = array(
          '' => '',
        );
        $states[$i]->raw_grade = 0;
      }

      // now fill/overide initial values
      $states[$i]->attempt = $attempt->uniqueid;
      $states[$i]->seq_number = 0;
      $states[$i]->timestamp = $attempt->timestart;
      $states[$i]->event = $attempt->timefinish ? QUESTION_EVENTCLOSE : QUESTION_EVENTOPEN;
      $states[$i]->grade = 0;
      $states[$i]->penalty = 0;
      $states[$i]->sumpenalty = 0;
      $states[$i]->manualcomment = '';

      // Prevent further changes to the session from incrementing the
      // sequence number
      $states[$i]->changed = true;
      if ($lastattemptid) {

        // prepare the previous responses for new processing
        $action = new stdClass();
        $action->responses = $laststate->responses;
        $action->timestamp = $laststate->timestamp;
        $action->event = QUESTION_EVENTSAVE;

        //emulate save of questions from all pages MDL-7631

        // Process these responses ...
        question_process_responses($questions[$i], $states[$i], $action, $cmoptions, $attempt);

        // Fix for Bug #5506: When each attempt is built on the last one,
        // preserve the options from any previous attempt.
        if (isset($laststate->options)) {
          $states[$i]->options = $laststate->options;
        }
      }
      else {

        // Create the empty question type specific information
        if (!$QTYPES[$questions[$i]->qtype]
          ->create_session_and_responses($questions[$i], $states[$i], $cmoptions, $attempt)) {
          return false;
        }
      }
      $states[$i]->last_graded = clone $states[$i];
    }
  }
  return $states;
}