/** * 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; }
$forcenew = optional_param('forcenew', false, PARAM_BOOL); // Used to force a new preview if (!($cm = get_coursemodule_from_id('quiz', $id))) { print_error('invalidcoursemodule'); } if (!($course = $DB->get_record('course', array('id' => $cm->course)))) { print_error("coursemisconf"); } if (!($quiz = $DB->get_record('quiz', array('id' => $cm->instance)))) { print_error('invalidcoursemodule'); } $quizobj = new quiz($quiz, $cm, $course); /// Check login and sesskey. require_login($quizobj->get_courseid(), false, $quizobj->get_cm()); if (!confirm_sesskey()) { throw new moodle_exception('confirmsesskeybad', 'error', $quizobj->view_url()); } /// if no questions have been set up yet redirect to edit.php if (!$quizobj->get_question_ids() && $quizobj->has_capability('mod/quiz:manage')) { redirect($quizobj->edit_url()); } /// Create an object to manage all the other (non-roles) access rules. $accessmanager = $quizobj->get_access_manager(time()); if ($quizobj->is_preview_user() && $forcenew) { $accessmanager->clear_password_access(); } /// Check capabilites. if (!$quizobj->is_preview_user()) { $quizobj->require_capability('mod/quiz:attempt'); } /// Check to see if a new preview was requested.
/** * 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; }