function quiz_take_quiz in Quiz 6.5
Same name and namespace in other branches
- 8.4 quiz.module \quiz_take_quiz()
- 5.2 quiz.module \quiz_take_quiz()
- 5 quiz.module \quiz_take_quiz()
- 6.6 quiz.module \quiz_take_quiz()
- 6.2 quiz.module \quiz_take_quiz()
- 6.3 quiz.module \quiz_take_quiz()
- 6.4 quiz.module \quiz_take_quiz()
- 7.6 quiz.module \quiz_take_quiz()
- 7 quiz.module \quiz_take_quiz()
- 7.4 quiz.module \quiz_take_quiz()
- 7.5 quiz.module \quiz_take_quiz()
Handles quiz taking.
This gets executed when the main quiz node is first loaded.
Parameters
$quiz: The quiz node.
Return value
HTML output for page.
1 call to quiz_take_quiz()
- quiz_view in ./
quiz.module - Implementation of hook_view().
File
- ./
quiz.module, line 985 - Quiz Module
Code
function quiz_take_quiz($quiz) {
global $user;
$allow_skipping = TRUE;
// If no access, fail.
if (!user_access('access quiz')) {
drupal_access_denied();
return;
}
if (!isset($quiz)) {
drupal_not_found();
return;
}
// If anonymous user and no unique hash, refresh with a unique string to prevent caching.
if (!$quiz->name && arg(4) == NULL) {
drupal_goto('node/' . $quiz->nid . '/quiz/start/' . md5(mt_rand() . time()));
}
if (!isset($_SESSION['quiz_' . $quiz->nid]['quiz_questions'])) {
$rid = _quiz_active_result_id($user->uid, $quiz->nid, $quiz->vid);
// Are we resuming an in-progress quiz?
if ($rid > 0) {
_quiz_resume_existing_quiz($quiz, $user->uid, $rid);
}
elseif ($rid = quiz_start_actions($quiz)) {
// Create question list.
$questions = quiz_build_question_list($quiz);
if ($questions === FALSE) {
drupal_set_message(t('Not enough random questions were found. Please !add more questions before trying to take this @quiz.', array(
'@quiz' => QUIZ_NAME,
'!add more questions' => l('add more questions', 'node/' . arg(1) . '/questions'),
)), 'error');
return array(
'body' => array(
'#value' => '',
),
);
}
if (count($questions) == 0) {
drupal_set_message(t('No questions were found. Please !assign questions before trying to take this @quiz.', array(
'@quiz' => QUIZ_NAME,
'!assign questions' => l('assign questions', 'node/' . arg(1) . '/questions'),
)), 'error');
return array(
'body' => array(
'#value' => '',
),
);
}
// Initialize session variables.
$_SESSION['quiz_' . $quiz->nid]['quiz_questions'] = $questions;
$_SESSION['quiz_' . $quiz->nid]['result_id'] = $rid;
$_SESSION['quiz_' . $quiz->nid]['question_number'] = 0;
$_SESSION['quiz_' . $quiz->nid]['question_start_time'] = time();
$_SESSION['quiz_' . $quiz->nid]['question_duration'] = $quiz->time_limit;
}
else {
return array(
'body' => array(
'#value' => '',
),
);
}
}
if (!isset($_POST['op'])) {
// Starting new quiz... Do we need to show instructions here?
}
elseif ($_POST['op'] == t('Back')) {
unset($_POST['tries']);
// We maintain two lists -- previous questions and upcomming questions.
// When we go backward, we pop one from the previous and prepend it to
// the upcomming.
// TODO: This can be maintained more efficiently with a single array of
// all questions and then a pointer to the current question. That makes
// rewinding much easier.
$quiz_id = 'quiz_' . $quiz->nid;
$last_q = array_pop($_SESSION[$quiz_id]['previous_quiz_questions']);
array_unshift($_SESSION[$quiz_id]['quiz_questions'], $last_q);
}
elseif ($_POST['op'] == t('Submit') || $_POST['op'] == t('Next')) {
if (!isset($_POST['tries'])) {
// Moving skip logic here...
if ($allow_skipping) {
// Advance the question.
$_SESSION['quiz_' . $quiz->nid]['previous_quiz_questions'][] = $_SESSION['quiz_' . $quiz->nid]['quiz_questions'][0];
// Load the last asked question.
$former_question_array = array_shift($_SESSION['quiz_' . $quiz->nid]['quiz_questions']);
$former_question = node_load(array(
'nid' => $former_question_array['nid'],
));
// Call hook_skip_question().
$module = quiz_module_for_type($former_question->type);
$result = module_invoke($module, 'skip_question', $former_question, $_SESSION['quiz_' . $quiz->nid]['result_id']);
// Report that the question was skipped:
//quiz_store_question_result($former_question_array['nid'], $former_question_array['vid'], $_SESSION['quiz_'. $quiz->nid]['result_id'], $result);
quiz_store_question_result($result, array(
'set_msg' => TRUE,
));
}
else {
drupal_set_message(t('You must select an answer before you can progress to the next question!'), 'error');
}
}
else {
//unset($_SESSION['quiz_'. $quiz->nid]['previous_quiz_questions']);
// Previous quiz questions: Questions that have been asked already. We save a record of all of them
// so that a user can navigate backward all the way to the beginning of the quiz.
$_SESSION['quiz_' . $quiz->nid]['previous_quiz_questions'][] = $_SESSION['quiz_' . $quiz->nid]['quiz_questions'][0];
$former_question_array = array_shift($_SESSION['quiz_' . $quiz->nid]['quiz_questions']);
$former_question = node_load(array(
'nid' => $former_question_array['nid'],
));
// Call hook_evaluate_question().
$types = _quiz_get_question_types();
$module = $types[$former_question->type]['module'];
//drupal_set_message($module . ' evaluate_question called');
$result = module_invoke($module, 'evaluate_question', $former_question, $_SESSION['quiz_' . $quiz->nid]['result_id']);
//$result stdClass Object ( [score] => 0 [nid] => 3 [vid] => 3 [rid] => 27 [is_correct] => [is_evaluated] => 1 [is_skipped] => )
quiz_store_question_result($result, array(
'set_msg' => TRUE,
));
// Stash feedback in the session, since the $_POST gets cleared.
if ($quiz->feedback_time == QUIZ_FEEDBACK_QUESTION) {
// Invoke hook_get_report().
//$report = module_invoke($former_question->type, 'get_report', $former_question_array['nid'], $former_question_array['vid'], $_SESSION['quiz_'. $quiz->nid]['result_id']);
$report = module_invoke($module, 'get_report', $former_question_array['nid'], $former_question_array['vid'], $_SESSION['quiz_' . $quiz->nid]['result_id']);
$_SESSION['quiz_' . $quiz->nid]['feedback'] = rawurlencode(quiz_get_feedback($quiz, $report));
}
// If anonymous user, refresh url with unique hash to prevent caching.
if (!$user->uid) {
//drupal_goto('node/'. $quiz->nid .'/quiz/start/'. md5(mt_rand() . time())); #460550
drupal_goto('node/' . $quiz->nid, array(
'quizkey' => md5(mt_rand() . time()),
));
}
}
}
elseif ($_POST['op'] == t('Skip') && $allow_skipping) {
// Advance the question.
$_SESSION['quiz_' . $quiz->nid]['previous_quiz_questions'][] = $_SESSION['quiz_' . $quiz->nid]['quiz_questions'][0];
// Load the last asked question.
$former_question_array = array_shift($_SESSION['quiz_' . $quiz->nid]['quiz_questions']);
$former_question = node_load(array(
'nid' => $former_question_array['nid'],
));
// Call hook_skip_question().
$module = quiz_module_for_type($former_question->type);
$result = module_invoke($module, 'skip_question', $former_question, $_SESSION['quiz_' . $quiz->nid]['result_id']);
// Report that the question was skipped:
//quiz_store_question_result($former_question_array['nid'], $former_question_array['vid'], $_SESSION['quiz_'. $quiz->nid]['result_id'], $result);
quiz_store_question_result($result, array(
'set_msg' => TRUE,
));
}
// The content array:
//$content['body'] = array();
// If we had feedback from the last question.
if (isset($_SESSION['quiz_' . $quiz->nid]['feedback']) && $quiz->feedback_time == QUIZ_FEEDBACK_QUESTION) {
$content['body']['feedback']['#value'] = rawurldecode($_SESSION['quiz_' . $quiz->nid]['feedback']);
//$output .= rawurldecode($_SESSION['quiz_'. $quiz->nid]['feedback']);
}
// If this quiz is in progress, load the next questions and return it via the theme.
if (!empty($_SESSION['quiz_' . $quiz->nid]['quiz_questions'])) {
$question_node = node_load(array(
'nid' => $_SESSION['quiz_' . $quiz->nid]['quiz_questions'][0]['nid'],
));
//$output .= theme('quiz_take_question', $quiz, $question_node);
// Start mods...
$number_of_questions = quiz_get_number_of_questions($quiz->vid, $quiz->nid);
$question_number = $number_of_questions - count($_SESSION['quiz_' . $quiz->nid]['quiz_questions']);
$question_node->question_number = $question_number;
$content['progress']['#value'] = theme('quiz_progress', $question_number, $number_of_questions);
$content['progress']['#weight'] = -50;
if ($_SESSION['quiz_' . $quiz->nid]['question_duration']) {
$_SESSION['quiz_' . $quiz->nid]['question_duration'] -= time() - $_SESSION['quiz_' . $quiz->nid]['question_start_time'];
/*
if ($_SESSION['quiz_'. $quiz->nid]['question_duration'] < -10) {
unset($_SESSION['quiz_'. $quiz->nid]);
drupal_set_message('You have left this quiz partially complete.');
return ;
}
*/
$time = $_SESSION['quiz_' . $quiz->nid]['question_duration'] > 0 ? $_SESSION['quiz_' . $quiz->nid]['question_duration'] : 1;
db_query("UPDATE {quiz_node_results} SET time_left = %d WHERE result_id = %d", $time, $_SESSION['quiz_' . $quiz->nid]['result_id']);
if ($time == 1) {
/* Quiz has been timed out, run a loop to mark the remaining questions
* as skipped */
while (!empty($_SESSION['quiz_' . $quiz->nid]['quiz_questions'])) {
$_SESSION['quiz_' . $quiz->nid]['previous_quiz_questions'][] = $_SESSION['quiz_' . $quiz->nid]['quiz_questions'][0];
$former_question_array = array_shift($_SESSION['quiz_' . $quiz->nid]['quiz_questions']);
$former_question = node_load(array(
'nid' => $former_question_array['nid'],
));
// Call hook_skip_question().
$module = quiz_module_for_type($former_question->type);
$result = module_invoke($module, 'skip_question', $former_question, $_SESSION['quiz_' . $quiz->nid]['result_id']);
// Report that the question was skipped:
//quiz_store_question_result($former_question_array['nid'], $former_question_array['vid'], $_SESSION['quiz_'. $quiz->nid]['result_id'], $result);
quiz_store_question_result($result, array(
'set_mesg' => FALSE,
));
}
$_SESSION['quiz_' . $quiz->nid]['quiz_questions'] = array();
// empty the quiz questions
// We're at the end of the quiz, so set a flag saying so.
$quiz_end = TRUE;
drupal_set_message(t('You have run out of time.'), 'error');
}
else {
// There is still time left, so let's go ahead and insert the countdown javascript.
if (function_exists('jquery_countdown_add') && variable_get('quiz_has_timer', 1)) {
jquery_countdown_add('.countdown', array(
'until' => $time,
'onExpiry' => 'finished',
));
drupal_add_js('function finished() { window.location = window.location.href; }', 'inline');
//window.location.reload() method doesn't works here.
}
}
$_SESSION['quiz_' . $quiz->nid]['question_start_time'] = time();
}
// If we're not yet at the end.
if (empty($quiz_end)) {
// Basically, we store the results of what would normally be a node_view() of the question node in
// the $content for the quiz node. Since we want to override the default theme, we use the
// quiz_node_view() function, which performs the steps in node_view(), but in a way more
// specific to our needs.
$content['body']['#value'] = quiz_node_view($question_node, TRUE, FALSE);
drupal_set_title(check_plain($quiz->title));
unset($_SESSION['quiz_' . $quiz->nid]['feedback']);
}
}
else {
$quiz_end = TRUE;
}
// If we're at the end of the quiz.
if (!empty($quiz_end)) {
$score = quiz_end_actions($quiz, $_SESSION['quiz_' . $quiz->nid]['result_id']);
//print_r($score);exit;Array ( [question_count] => 2 [possible_score] => 2 [numeric_score] => 2 [percentage_score] => 100 [is_evaluated] => 1 )
if ($quiz->feedback_time == QUIZ_FEEDBACK_NEVER) {
$content['body']['#value'] = theme('quiz_no_feedback');
}
else {
// Get the results and summary text for this quiz.
$questions = _quiz_get_answers($_SESSION['quiz_' . $quiz->nid]['result_id']);
$summary = _quiz_get_summary_text($quiz, $score);
// Get the themed summary page.
$content['body']['#value'] = theme('quiz_take_summary', $quiz, $questions, $score, $summary);
}
// Remove session variables.
unset($_SESSION['quiz_' . $quiz->nid]);
}
//return $output;
return $content;
}