Skip to main content

Insight | Nov 13, 2015

Customizing the Quiz Module for Every Need in Drupal

By Josh Fremer

The Drupal Quiz module provides a great foundation to build scored assessments in Drupal. It offers a range of scoring customizations, but it can't fill every need out of the box.

Fortunately, Quiz also offers robust API exposed through a collection of hooks. If you have custom logic that impacts your scoring, hook_quiz_finished is for you. This hook allows you to modify any properties of a quiz result when it's saved.

In my case, I had the requirement that any questions answered "N/A" should be subtracted from the denominator of the scoring equation. So, for instance, if a quiz had 10 questions and had 1 correct answer, 1 incorrect answer and 8 "N/A", the quiz score would be 50% (1/2).

 

/**
 * Implements hook_quiz_finished().
 *
 * If a question is answered "N/A", that question doesn't count toward the total
 * possible score.
 */
function mymodule_quiz_finished($quiz, $score, $data) {
  $possible_score = $score['possible_score'];
 
  // Here we're going to count up the number of 'N/A' answers.
  $query = db_select('quiz_node_results_answers', 'qra');
  $query->join('quiz_multichoice_user_answers', 'qmua', 'qra.result_answer_id = qmua.result_answer_id');
  $query->join('quiz_multichoice_user_answer_multi', 'qmuam', 'qmua.id = qmuam.user_answer_id');
  $query->join('quiz_multichoice_answers', 'qma', 'qmuam.answer_id = qma.id');
  $query->condition('qra.result_id', $data['result_id']);
  $query->condition('qma.answer', t('N/A'));
  $query->fields('qra', array('result_answer_id'));
 
  $na_answers = $query->execute()->rowCount();
 
  // Subtract the total from the highest possible score.
  $possible_score = $possible_score - $na_answers;
 
  // Then recalculate the score.
  $quiz_result = quiz_result_load($data['result_id']);
  if ($possible_score > 0) {
    $quiz_result->score = ($score['numeric_score'] / $possible_score) * 100;
  }
  else {
    $quiz_result->score = 0;
  }
  entity_save('quiz_result', $quiz_result);
}

 

hook_quiz_finished implementations take three arguments:

  1. The quiz entity for which a new result was recorded.
  2. An associative array of scoring data, including possible_score (the number of total questions encountered) and numeric_score (the number of correct answers).
  3. An associative array of information about the quiz result record, including result_id which you can use to load the full result entity for updating.

In my example above I query for a count of all "N/A" answers recorded for the quiz result in question (this takes a few joins). Then I simply subtract that count from the number of possible answers and re-calculate the score. As far as the Drupal Quiz module is concerned, scoring is finished for this result; it never goes back and re-calculates so your custom-calculated score is safe and ready for display.

Drop us a line

Have a project in mind?

Contacting Third and Grove may cause awesomeness. Side effects include a website too good to ignore. Proceed at your own risk.

Reduced motion disabled