* @param int $timestamp the timestamp that should be stored as the modifed
* time in the database for these actions. If null, will use the current time.
*/
- public function process_submitted_actions($timestamp, $becomingoverdue = false) {
+ public function process_submitted_actions($timestamp, $becomingoverdue = false, $postdata = null) {
global $DB;
$transaction = $DB->start_delegated_transaction();
- $this->quba->process_all_actions($timestamp);
+ $this->quba->process_all_actions($timestamp, $postdata);
question_engine::save_questions_usage_by_activity($this->quba);
$this->attempt->timemodified = $timestamp;
return $attempt;
}
+/**
+ * Start a normal, new, quiz attempt.
+ *
+ * @param quiz $quizobj the quiz object to start an attempt for.
+ * @param question_usage_by_activity $quba
+ * @param object $attempt
+ * @param integer $attemptnumber starting from 1
+ * @param integer $timenow the attempt start time
+ * @return object modified attempt object
+ * @throws moodle_exception if a random question exhausts the available questions
+ */
+function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow) {
+ // Fully load all the questions in this quiz.
+ $quizobj->preload_questions();
+ $quizobj->load_questions();
+
+ // Add them all to the $quba.
+ $idstoslots = array();
+ $questionsinuse = array_keys($quizobj->get_questions());
+ foreach ($quizobj->get_questions() as $i => $questiondata) {
+ if ($questiondata->qtype != 'random') {
+ if (!$quizobj->get_quiz()->shuffleanswers) {
+ $questiondata->options->shuffleanswers = false;
+ }
+ $question = question_bank::make_question($questiondata);
+
+ } else {
+ $question = question_bank::get_qtype('random')->choose_other_question(
+ $questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers);
+ if (is_null($question)) {
+ throw new moodle_exception('notenoughrandomquestions', 'quiz',
+ $quizobj->view_url(), $questiondata);
+ }
+ }
+
+ $idstoslots[$i] = $quba->add_question($question, $questiondata->maxmark);
+ $questionsinuse[] = $question->id;
+ }
+
+ // Start all the questions.
+ if ($attempt->preview) {
+ $variantoffset = rand(1, 100);
+ } else {
+ $variantoffset = $attemptnumber;
+ }
+ $quba->start_all_questions(
+ new question_variant_pseudorandom_no_repeats_strategy($variantoffset), $timenow);
+
+ // Update attempt layout.
+ $newlayout = array();
+ foreach (explode(',', $attempt->layout) as $qid) {
+ if ($qid != 0) {
+ $newlayout[] = $idstoslots[$qid];
+ } else {
+ $newlayout[] = 0;
+ }
+ }
+ $attempt->layout = implode(',', $newlayout);
+ return $attempt;
+}
+
+/**
+ * Start a subsequent new attempt, in each attempt builds on last mode.
+ *
+ * @param question_usage_by_activity $quba this question usage
+ * @param object $attempt this attempt
+ * @param object $lastattempt last attempt
+ * @return object modified attempt object
+ *
+ */
+function quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt) {
+ $oldquba = question_engine::load_questions_usage_by_activity($lastattempt->uniqueid);
+
+ $oldnumberstonew = array();
+ foreach ($oldquba->get_attempt_iterator() as $oldslot => $oldqa) {
+ $newslot = $quba->add_question($oldqa->get_question(), $oldqa->get_max_mark());
+
+ $quba->start_question_based_on($newslot, $oldqa);
+
+ $oldnumberstonew[$oldslot] = $newslot;
+ }
+
+ // Update attempt layout.
+ $newlayout = array();
+ foreach (explode(',', $lastattempt->layout) as $oldslot) {
+ if ($oldslot != 0) {
+ $newlayout[] = $oldnumberstonew[$oldslot];
+ } else {
+ $newlayout[] = 0;
+ }
+ }
+ $attempt->layout = implode(',', $newlayout);
+ return $attempt;
+}
+
+/**
+ * The save started question usage and quiz attempt in db and log the started attempt.
+ *
+ * @param quiz $quizobj
+ * @param question_usage_by_activity $quba
+ * @param object $attempt
+ * @return object attempt object with uniqueid and id set.
+ */
+function quiz_attempt_save_started($quizobj, $quba, $attempt) {
+ global $DB;
+ // Save the attempt in the database.
+ question_engine::save_questions_usage_by_activity($quba);
+ $attempt->uniqueid = $quba->get_id();
+ $attempt->id = $DB->insert_record('quiz_attempts', $attempt);
+ // Log the new attempt.
+ if ($attempt->preview) {
+ add_to_log($quizobj->get_courseid(), 'quiz', 'preview', 'view.php?id='.$quizobj->get_cmid(),
+ $quizobj->get_quizid(), $quizobj->get_cmid());
+ } else {
+ add_to_log($quizobj->get_courseid(), 'quiz', 'attempt', 'review.php?attempt='.$attempt->id,
+ $quizobj->get_quizid(), $quizobj->get_cmid());
+ }
+ return $attempt;
+}
+
+/**
+ * Fire an event to tell the rest of Moodle a quiz attempt has started.
+ *
+ * @param object $attempt
+ * @param quiz $quizobj
+ */
+function quiz_fire_attempt_started_event($attempt, $quizobj) {
+ // Trigger event.
+ $eventdata = new stdClass();
+ $eventdata->component = 'mod_quiz';
+ $eventdata->attemptid = $attempt->id;
+ $eventdata->timestart = $attempt->timestart;
+ $eventdata->timestamp = $attempt->timestart;
+ $eventdata->userid = $attempt->userid;
+ $eventdata->quizid = $quizobj->get_quizid();
+ $eventdata->cmid = $quizobj->get_cmid();
+ $eventdata->courseid = $quizobj->get_courseid();
+ events_trigger('quiz_attempt_started', $eventdata);
+}
/**
* Returns an unfinished attempt (if there is one) for the given
// Create the new attempt and initialize the question sessions
$timenow = time(); // Update time now, in case the server is running really slowly.
-$attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow,
- $quizobj->is_preview_user());
+$attempt = quiz_create_attempt($quizobj, $attemptnumber, $lastattempt, $timenow, $quizobj->is_preview_user());
if (!($quizobj->get_quiz()->attemptonlast && $lastattempt)) {
- // Starting a normal, new, quiz attempt.
-
- // Fully load all the questions in this quiz.
- $quizobj->preload_questions();
- $quizobj->load_questions();
-
- // Add them all to the $quba.
- $idstoslots = array();
- $questionsinuse = array_keys($quizobj->get_questions());
- foreach ($quizobj->get_questions() as $i => $questiondata) {
- if ($questiondata->qtype != 'random') {
- if (!$quizobj->get_quiz()->shuffleanswers) {
- $questiondata->options->shuffleanswers = false;
- }
- $question = question_bank::make_question($questiondata);
-
- } else {
- $question = question_bank::get_qtype('random')->choose_other_question(
- $questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers);
- if (is_null($question)) {
- throw new moodle_exception('notenoughrandomquestions', 'quiz',
- $quizobj->view_url(), $questiondata);
- }
- }
-
- $idstoslots[$i] = $quba->add_question($question, $questiondata->maxmark);
- $questionsinuse[] = $question->id;
- }
-
- // Start all the questions.
- if ($attempt->preview) {
- $variantoffset = rand(1, 100);
- } else {
- $variantoffset = $attemptnumber;
- }
- $quba->start_all_questions(
- new question_variant_pseudorandom_no_repeats_strategy($variantoffset), $timenow);
-
- // Update attempt layout.
- $newlayout = array();
- foreach (explode(',', $attempt->layout) as $qid) {
- if ($qid != 0) {
- $newlayout[] = $idstoslots[$qid];
- } else {
- $newlayout[] = 0;
- }
- }
- $attempt->layout = implode(',', $newlayout);
-
+ $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow);
} else {
- // Starting a subsequent attempt in each attempt builds on last mode.
-
- $oldquba = question_engine::load_questions_usage_by_activity($lastattempt->uniqueid);
-
- $oldnumberstonew = array();
- foreach ($oldquba->get_attempt_iterator() as $oldslot => $oldqa) {
- $newslot = $quba->add_question($oldqa->get_question(), $oldqa->get_max_mark());
-
- $quba->start_question_based_on($newslot, $oldqa);
-
- $oldnumberstonew[$oldslot] = $newslot;
- }
-
- // Update attempt layout.
- $newlayout = array();
- foreach (explode(',', $lastattempt->layout) as $oldslot) {
- if ($oldslot != 0) {
- $newlayout[] = $oldnumberstonew[$oldslot];
- } else {
- $newlayout[] = 0;
- }
- }
- $attempt->layout = implode(',', $newlayout);
+ $attempt = quiz_start_attempt_built_on_last($quba, $attempt, $lastattempt);
}
-// Save the attempt in the database.
$transaction = $DB->start_delegated_transaction();
-question_engine::save_questions_usage_by_activity($quba);
-$attempt->uniqueid = $quba->get_id();
-$attempt->id = $DB->insert_record('quiz_attempts', $attempt);
-
-// Log the new attempt.
-if ($attempt->preview) {
- add_to_log($course->id, 'quiz', 'preview', 'view.php?id=' . $quizobj->get_cmid(),
- $quizobj->get_quizid(), $quizobj->get_cmid());
-} else {
- add_to_log($course->id, 'quiz', 'attempt', 'review.php?attempt=' . $attempt->id,
- $quizobj->get_quizid(), $quizobj->get_cmid());
-}
-// Trigger event.
-$eventdata = new stdClass();
-$eventdata->component = 'mod_quiz';
-$eventdata->attemptid = $attempt->id;
-$eventdata->timestart = $attempt->timestart;
-$eventdata->timestamp = $attempt->timestart;
-$eventdata->userid = $attempt->userid;
-$eventdata->quizid = $quizobj->get_quizid();
-$eventdata->cmid = $quizobj->get_cmid();
-$eventdata->courseid = $quizobj->get_courseid();
-events_trigger('quiz_attempt_started', $eventdata);
+$attempt = quiz_attempt_save_started($quizobj, $quba, $attempt);
+quiz_fire_attempt_started_event($attempt, $quizobj);
$transaction->allow_commit();