/** * 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 * @param array $questionids slot number => question id. Used for random questions, to force the choice * of a particular actual question. Intended for testing purposes only. * @param array $forcedvariantsbyslot slot number => variant. Used for questions with variants, * to force the choice of a particular variant. Intended for testing * purposes only. * @throws moodle_exception * @return object modified attempt object */ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $questionids = array(), $forcedvariantsbyslot = array()) { // 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 { if (!isset($questionids[$quba->next_slot_number()])) { $forcequestionid = null; } else { $forcequestionid = $questionids[$quba->next_slot_number()]; } $question = question_bank::get_qtype('random')->choose_other_question( $questiondata, $questionsinuse, $quizobj->get_quiz()->shuffleanswers, $forcequestionid); 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; } $variantstrategy = new question_variant_pseudorandom_no_repeats_strategy( $variantoffset, $attempt->userid, $quizobj->get_quizid()); if (!empty($forcedvariantsbyslot)) { $forcedvariantsbyseed = question_variant_forced_choices_selection_strategy::prepare_forced_choices_array( $forcedvariantsbyslot, $quba); $variantstrategy = new question_variant_forced_choices_selection_strategy( $forcedvariantsbyseed, $variantstrategy); } $quba->start_all_questions($variantstrategy, $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; }
if (!$quizobj->is_preview_user() && $messages) { print_error('attempterror', 'quiz', $quizobj->view_url(), $accessmanager->print_messages($messages, true)); } $accessmanager->do_password_check($quizobj->is_preview_user()); /// Delete any previous preview attempts belonging to this user. quiz_delete_previews($quiz, $USER->id); /// Create the new attempt and initialize the question sessions $attempt = quiz_create_attempt($quiz, $attemptnumber, $lastattempt, time(), $quizobj->is_preview_user()); /// Save the attempt in the database. if (!($attempt->id = $DB->insert_record('quiz_attempts', $attempt))) { quiz_error($quiz, 'newattemptfail'); } /// 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()); } /// Fully load all the questions in this quiz. $quizobj->preload_questions(); $quizobj->load_questions(); /// Create initial states for all questions in this quiz. if (!($states = get_question_states($quizobj->get_questions(), $quizobj->get_quiz(), $attempt, $lastattemptid))) { print_error('cannotrestore', 'quiz'); } /// Save all the newly created states. foreach ($quizobj->get_questions() as $i => $question) { save_question_session($question, $states[$i]); } /// Redirect to the attempt page. redirect($quizobj->attempt_url($attempt->id));
/** * 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 * @param array $questionids slot number => question id. Used for random questions, to force the choice * of a particular actual question. Intended for testing purposes only. * @param array $forcedvariantsbyslot slot number => variant. Used for questions with variants, * to force the choice of a particular variant. Intended for testing * purposes only. * @throws moodle_exception * @return object modified attempt object */ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $questionids = array(), $forcedvariantsbyslot = array()) { // Usages for this user's previous quiz attempts. $qubaids = new \mod_quiz\question\qubaids_for_users_attempts($quizobj->get_quizid(), $attempt->userid); // Fully load all the questions in this quiz. $quizobj->preload_questions(); $quizobj->load_questions(); // First load all the non-random questions. $randomfound = false; $slot = 0; $questions = array(); $maxmark = array(); $page = array(); foreach ($quizobj->get_questions() as $questiondata) { $slot += 1; $maxmark[$slot] = $questiondata->maxmark; $page[$slot] = $questiondata->page; if ($questiondata->qtype == 'random') { $randomfound = true; continue; } if (!$quizobj->get_quiz()->shuffleanswers) { $questiondata->options->shuffleanswers = false; } $questions[$slot] = question_bank::make_question($questiondata); } // Then find a question to go in place of each random question. if ($randomfound) { $slot = 0; $usedquestionids = array(); foreach ($questions as $question) { if (isset($usedquestions[$question->id])) { $usedquestionids[$question->id] += 1; } else { $usedquestionids[$question->id] = 1; } } $randomloader = new \core_question\bank\random_question_loader($qubaids, $usedquestionids); foreach ($quizobj->get_questions() as $questiondata) { $slot += 1; if ($questiondata->qtype != 'random') { continue; } // Deal with fixed random choices for testing. if (isset($questionids[$quba->next_slot_number()])) { if ($randomloader->is_question_available($questiondata->category, (bool) $questiondata->questiontext, $questionids[$quba->next_slot_number()])) { $questions[$slot] = question_bank::load_question($questionids[$quba->next_slot_number()], $quizobj->get_quiz()->shuffleanswers); continue; } else { throw new coding_exception('Forced question id not available.'); } } // Normal case, pick one at random. $questionid = $randomloader->get_next_question_id($questiondata->category, (bool) $questiondata->questiontext); if ($questionid === null) { throw new moodle_exception('notenoughrandomquestions', 'quiz', $quizobj->view_url(), $questiondata); } $questions[$slot] = question_bank::load_question($questionid, $quizobj->get_quiz()->shuffleanswers); } } // Finally add them all to the usage. ksort($questions); foreach ($questions as $slot => $question) { $newslot = $quba->add_question($question, $maxmark[$slot]); if ($newslot != $slot) { throw new coding_exception('Slot numbers have got confused.'); } } // Start all the questions. $variantstrategy = new core_question\engine\variants\least_used_strategy($quba, $qubaids); if (!empty($forcedvariantsbyslot)) { $forcedvariantsbyseed = question_variant_forced_choices_selection_strategy::prepare_forced_choices_array($forcedvariantsbyslot, $quba); $variantstrategy = new question_variant_forced_choices_selection_strategy($forcedvariantsbyseed, $variantstrategy); } $quba->start_all_questions($variantstrategy, $timenow); // Work out the attempt layout. $sections = $quizobj->get_sections(); foreach ($sections as $i => $section) { if (isset($sections[$i + 1])) { $sections[$i]->lastslot = $sections[$i + 1]->firstslot - 1; } else { $sections[$i]->lastslot = count($questions); } } $layout = array(); foreach ($sections as $section) { if ($section->shufflequestions) { $questionsinthissection = array(); for ($slot = $section->firstslot; $slot <= $section->lastslot; $slot += 1) { $questionsinthissection[] = $slot; } shuffle($questionsinthissection); $questionsonthispage = 0; foreach ($questionsinthissection as $slot) { if ($questionsonthispage && $questionsonthispage == $quizobj->get_quiz()->questionsperpage) { $layout[] = 0; $questionsonthispage = 0; } $layout[] = $slot; $questionsonthispage += 1; } } else { $currentpage = $page[$section->firstslot]; for ($slot = $section->firstslot; $slot <= $section->lastslot; $slot += 1) { if ($currentpage !== null && $page[$slot] != $currentpage) { $layout[] = 0; } $layout[] = $slot; $currentpage = $page[$slot]; } } // Each section ends with a page break. $layout[] = 0; } $attempt->layout = implode(',', $layout); return $attempt; }