Ejemplo n.º 1
0
 /**
  * Create a question_attempt_step from records loaded from the database.
  *
  * For internal use only.
  *
  * @param Iterator $records Raw records loaded from the database.
  * @param int $questionattemptid The id of the question_attempt to extract.
  * @return question_attempt The newly constructed question_attempt.
  */
 public static function load_from_records($records, $questionattemptid, question_usage_observer $observer, $preferredbehaviour)
 {
     $record = $records->current();
     while ($record->questionattemptid != $questionattemptid) {
         $record = $records->next();
         if (!$records->valid()) {
             throw new coding_exception("Question attempt {$questionattemptid} not found in the database.");
         }
         $record = $records->current();
     }
     try {
         $question = question_bank::load_question($record->questionid);
     } catch (Exception $e) {
         // The question must have been deleted somehow. Create a missing
         // question to use in its place.
         $question = question_bank::get_qtype('missingtype')->make_deleted_instance($record->questionid, $record->maxmark + 0);
     }
     $qa = new question_attempt($question, $record->questionusageid, null, $record->maxmark + 0);
     $qa->set_database_id($record->questionattemptid);
     $qa->set_slot($record->slot);
     $qa->variant = $record->variant + 0;
     $qa->minfraction = $record->minfraction + 0;
     $qa->maxfraction = $record->maxfraction + 0;
     $qa->set_flagged($record->flagged);
     $qa->questionsummary = $record->questionsummary;
     $qa->rightanswer = $record->rightanswer;
     $qa->responsesummary = $record->responsesummary;
     $qa->timemodified = $record->timemodified;
     $qa->behaviour = question_engine::make_behaviour($record->behaviour, $qa, $preferredbehaviour);
     $qa->observer = $observer;
     // If attemptstepid is null (which should not happen, but has happened
     // due to corrupt data, see MDL-34251) then the current pointer in $records
     // will not be advanced in the while loop below, and we get stuck in an
     // infinite loop, since this method is supposed to always consume at
     // least one record. Therefore, in this case, advance the record here.
     if (is_null($record->attemptstepid)) {
         $records->next();
     }
     $i = 0;
     $autosavedstep = null;
     $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());
         if ($sequencenumber < 0) {
             if (!$autosavedstep) {
                 $autosavedstep = $nextstep;
                 $autosavedsequencenumber = -$sequencenumber;
             } else {
                 // Old redundant data. Mark it for deletion.
                 $qa->observer->notify_step_deleted($nextstep, $qa);
             }
         } else {
             $qa->steps[$i] = $nextstep;
             if ($i == 0) {
                 $question->apply_attempt_state($qa->steps[0]);
             }
             $i++;
         }
         if ($records->valid()) {
             $record = $records->current();
         } else {
             $record = false;
         }
     }
     if ($autosavedstep) {
         if ($autosavedsequencenumber >= $i) {
             $qa->autosavedstep = $autosavedstep;
             $qa->steps[$i] = $qa->autosavedstep;
         } else {
             $qa->observer->notify_step_deleted($autosavedstep, $qa);
         }
     }
     return $qa;
 }
Ejemplo n.º 2
0
 /**
  * Store an entire {@link question_attempt} in the database,
  * including all the question_attempt_steps that comprise it.
  * @param question_attempt $qa the question attempt to store.
  * @param context $context the context of the owning question_usage_by_activity.
  */
 public function insert_question_attempt(question_attempt $qa, $context)
 {
     $record = new stdClass();
     $record->questionusageid = $qa->get_usage_id();
     $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->maxfraction = $qa->get_max_fraction();
     $record->flagged = $qa->is_flagged();
     $record->questionsummary = $qa->get_question_summary();
     if (core_text::strlen($record->questionsummary) > question_bank::MAX_SUMMARY_LENGTH) {
         // It seems some people write very long quesions! MDL-30760
         $record->questionsummary = core_text::substr($record->questionsummary, 0, question_bank::MAX_SUMMARY_LENGTH - 3) . '...';
     }
     $record->rightanswer = $qa->get_right_answer_summary();
     $record->responsesummary = $qa->get_response_summary();
     $record->timemodified = time();
     $record->id = $this->db->insert_record('question_attempts', $record);
     $qa->set_database_id($record->id);
     foreach ($qa->get_step_iterator() as $seq => $step) {
         $this->insert_question_attempt_step($step, $record->id, $seq, $context);
     }
 }
Ejemplo n.º 3
0
    /**
     * Create a question_attempt_step from records loaded from the database.
     *
     * For internal use only.
     *
     * @param Iterator $records Raw records loaded from the database.
     * @param int $questionattemptid The id of the question_attempt to extract.
     * @return question_attempt The newly constructed question_attempt.
     */
    public static function load_from_records($records, $questionattemptid,
            question_usage_observer $observer, $preferredbehaviour) {
        $record = $records->current();
        while ($record->questionattemptid != $questionattemptid) {
            $record = $records->next();
            if (!$records->valid()) {
                throw new coding_exception("Question attempt $questionattemptid not found in the database.");
            }
            $record = $records->current();
        }

        try {
            $question = question_bank::load_question($record->questionid);
        } catch (Exception $e) {
            // The question must have been deleted somehow. Create a missing
            // question to use in its place.
            $question = question_bank::get_qtype('missingtype')->make_deleted_instance(
                    $record->questionid, $record->maxmark + 0);
        }

        $qa = new question_attempt($question, $record->questionusageid,
                null, $record->maxmark + 0);
        $qa->set_database_id($record->questionattemptid);
        $qa->set_slot($record->slot);
        $qa->variant = $record->variant + 0;
        $qa->minfraction = $record->minfraction + 0;
        $qa->set_flagged($record->flagged);
        $qa->questionsummary = $record->questionsummary;
        $qa->rightanswer = $record->rightanswer;
        $qa->responsesummary = $record->responsesummary;
        $qa->timemodified = $record->timemodified;

        $qa->behaviour = question_engine::make_behaviour(
                $record->behaviour, $qa, $preferredbehaviour);

        $i = 0;
        while ($record && $record->questionattemptid == $questionattemptid && !is_null($record->attemptstepid)) {
            $qa->steps[$i] = question_attempt_step::load_from_records($records, $record->attemptstepid);
            if ($i == 0) {
                $question->apply_attempt_state($qa->steps[0]);
            }
            $i++;
            if ($records->valid()) {
                $record = $records->current();
            } else {
                $record = false;
            }
        }

        $qa->observer = $observer;

        return $qa;
    }
Ejemplo n.º 4
0
    /**
     * Regrade a question in this usage. This replays the sequence of submitted
     * actions to recompute the outcomes.
     * @param int $slot the number used to identify this question within this usage.
     * @param bool $finished whether the question attempt should be forced to be finished
     *      after the regrade, or whether it may still be in progress (default false).
     * @param number $newmaxmark (optional) if given, will change the max mark while regrading.
     */
    public function regrade_question($slot, $finished = false, $newmaxmark = null) {
        $oldqa = $this->get_question_attempt($slot);
        if (is_null($newmaxmark)) {
            $newmaxmark = $oldqa->get_max_mark();
        }

        $newqa = new question_attempt($oldqa->get_question(), $oldqa->get_usage_id(),
                $this->observer, $newmaxmark);
        $newqa->set_database_id($oldqa->get_database_id());
        $newqa->set_slot($oldqa->get_slot());
        $newqa->regrade($oldqa, $finished);

        $this->questionattempts[$slot] = $newqa;
        $this->observer->notify_attempt_modified($newqa);
    }
Ejemplo n.º 5
0
 /**
  * Store an entire {@link question_attempt} in the database,
  * including all the question_attempt_steps that comprise it.
  *
  * You should not call this method directly. You should use
  * @link question_engine::save_questions_usage_by_activity()}.
  *
  * @param question_attempt $qa the question attempt to store.
  * @param context $context the context of the owning question_usage_by_activity.
  * @return array of question_attempt_step_data rows, that still need to be inserted.
  */
 public function insert_question_attempt(question_attempt $qa, $context)
 {
     $record = new stdClass();
     $record->questionusageid = $qa->get_usage_id();
     $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->maxfraction = $qa->get_max_fraction();
     $record->flagged = $qa->is_flagged();
     $record->questionsummary = $qa->get_question_summary();
     if (core_text::strlen($record->questionsummary) > question_bank::MAX_SUMMARY_LENGTH) {
         // It seems some people write very long quesions! MDL-30760
         $record->questionsummary = core_text::substr($record->questionsummary, 0, question_bank::MAX_SUMMARY_LENGTH - 3) . '...';
     }
     $record->rightanswer = $qa->get_right_answer_summary();
     $record->responsesummary = $qa->get_response_summary();
     $record->timemodified = time();
     $record->id = $this->db->insert_record('question_attempts', $record);
     $qa->set_database_id($record->id);
     // Initially an array of array of question_attempt_step_objects.
     // Built as a nested array for efficiency, then flattened.
     $stepdata = array();
     foreach ($qa->get_step_iterator() as $seq => $step) {
         $stepdata[] = $this->insert_question_attempt_step($step, $record->id, $seq, $context);
     }
     return call_user_func_array('array_merge', $stepdata);
 }