You are here

abstract class QuizQuestionResponse in OG Quiz 7

Each question type must store its own response data and be able to calculate a score for that data.

Hierarchy

Expanded class hierarchy of QuizQuestionResponse

File

includes/og_quiz_question.php, line 743
Classes used in the Quiz Question module.

View source
abstract class QuizQuestionResponse {

  // Result id
  protected $rid = 0;
  protected $is_correct = FALSE;
  protected $evaluated = TRUE;

  // The question node(not a quiz question instance)
  public $question = NULL;
  protected $answer = NULL;
  protected $score;
  public $is_skipped;
  public $is_doubtful;

  /**
   * Create a new user response.
   *
   * @param $result_id
   *  The result ID for the user's result set. There is one result ID per time
   *  the user takes a quiz.
   * @param $question_node
   *  The question node.
   * @param $answer
   *  The answer (dependent on question type).
   */
  public function __construct($result_id, stdClass $question_node, $answer = NULL) {
    $this->rid = $result_id;
    $this->question = $question_node;
    $this->answer = $answer;
    $result = db_query('SELECT is_skipped, is_doubtful FROM {quiz_node_results_answers}
            WHERE result_id = :result_id AND question_nid = :question_nid AND question_vid = :question_vid', array(
      ':result_id' => $result_id,
      ':question_nid' => $question_node->nid,
      ':question_vid' => $question_node->vid,
    ))
      ->fetch();
    if (is_object($result)) {
      $this->is_doubtful = $result->is_doubtful;
      $this->is_skipped = $result->is_skipped;
    }
  }

  /**
   * Used to refresh this instances question node in case drupal has changed it.
   *
   * @param $newNode
   *  Question node
   */
  public function refreshQuestionNode($newNode) {
    $this->question = $newNode;
  }

  /**
   * Indicate whether the response has been evaluated (scored) yet.
   * Questions that require human scoring (e.g. essays) may need to manually
   * toggle this.
   */
  public function isEvaluated() {
    return (bool) $this->evaluated;
  }

  /**
   * Check to see if the answer is marked as correct.
   *
   * This default version returns TRUE iff the score is equal to the maximum possible score.
   */
  function isCorrect() {
    return $this
      ->getMaxScore() == $this
      ->getScore();
  }

  /**
   * Helper function to determine if a user has access to score a quiz.
   *
   * @param $quiz_creator
   *   uid of the quiz creator.
   *
   * @return bool
   */
  public function quizContextAccessToScore($quiz_creator = NULL) {

    // Must we check this node, or the parent quiz ?
    if (!isset($this->checkWhat)) {
      if (isset($this->question->nid) && og_is_group_content_type('node', $this->question->type)) {
        $groups = og_get_entity_groups('node', $this->node);
        if (!empty($groups)) {
          $this->checkWhat = 'self';
        }
      }

      // If empty, check the parent quiz.
      if (!isset($this->checkWhat)) {

        // Try fetching the parent quiz, if any.
        $quiz = $this
          ->getParentQuiz();
        if (isset($quiz)) {
          $this->checkWhat = 'parent';
        }
        else {

          // Use default permissions.
          $this->checkWhat = 'none';
        }
      }
    }
    if ($this->checkWhat != 'none') {
      if ($this->checkWhat == 'parent') {
        $node = $this
          ->getParentQuiz();
      }
      else {
        $node = clone $this->question;
      }
      if ($quiz_creator == NULL && ($quiz = quiz_get_quiz_from_menu())) {
        $quiz_creator = $quiz->uid;
      }
      if (!($access = og_quiz_ogs_access($node, array(
        'score taken quiz answer',
        'score taken quiz answer',
      )))) {
        $access = og_quiz_ogs_access($node, 'score own quiz');
        if ($access) {
          global $user;
          $access = $access && $user->uid == $quiz_creator;
        }
      }
    }
    return isset($access) ? $access : quiz_access_to_score($quiz_creator);
  }

  /**
   * Fetch the parent quiz.
   *
   * @return stdClass|null
   */
  public function getParentQuiz() {
    if (isset($this->question->nid)) {
      $quiz = db_select('quiz_node_relationship', 'r')
        ->fields('r', array(
        'parent_nid',
        'parent_vid',
      ))
        ->condition('child_nid', $this->question->nid)
        ->condition('child_vid', $this->question->vid)
        ->execute()
        ->fetchObject();
      if (isset($quiz->nid)) {
        return node_load($quiz->nid, $quiz->vid);
      }
    }
    return NULL;
  }

  /**
   * Returns stored score if it exists, if not the score is calculated and returned.
   *
   * @param $weight_adjusted
   *  If the returned score shall be adjusted according to the max_score the question has in a quiz
   * @return
   *  Score(int)
   */
  function getScore($weight_adjusted = TRUE) {
    if ($this->is_skipped) {
      return 0;
    }
    if (!isset($this->score)) {
      $this->score = $this
        ->score();
    }
    if (isset($this->question->score_weight) && $weight_adjusted) {
      return round($this->score * $this->question->score_weight);
    }
    return $this->score;
  }

  /**
   * Returns stored max score if it exists, if not the max score is calculated and returned.
   *
   * @param $weight_adjusted
   *  If the returned max score shall be adjusted according to the max_score the question has in a quiz
   * @return
   *  Max score(int)
   */
  public function getMaxScore($weight_adjusted = TRUE) {
    if (!isset($this->question->max_score)) {
      $this->question->max_score = 1;
    }
    if (isset($this->question->score_weight) && $weight_adjusted) {
      return round($this->question->max_score * $this->question->score_weight);
    }
    return $this->question->max_score;
  }

  /**
   * Represent the response as a stdClass object.
   *
   * Convert data to an object that has the following properties:
   * - $score
   * - $rid
   * - $nid
   * - $vid
   * - $is_correct
   */
  function toBareObject() {
    $obj = new stdClass();
    $obj->score = $this
      ->getScore();

    // This can be 0 for unscored.
    $obj->nid = $this->question->nid;
    $obj->vid = $this->question->vid;
    $obj->rid = $this->rid;
    $obj->is_correct = (int) $this
      ->isCorrect();
    $obj->is_evaluated = $this
      ->isEvaluated();
    $obj->is_skipped = 0;
    $obj->is_doubtful = isset($_POST['is_doubtful']) ? $_POST['is_doubtful'] : 0;
    $obj->is_valid = $this
      ->isValid();
    return $obj;
  }

  /**
   * Validates response from a quiz taker. If the response isn't valid the quiz taker won't be allowed to proceed.
   *
   * @return
   *  True if the response is valid.
   *  False otherwise
   */
  public function isValid() {
    return TRUE;
  }

  /**
   * Get data suitable for reporting a user's score on the question.
   * This expects an object with the following attributes:
   *
   *  answer_id; // The answer ID
   *  answer; // The full text of the answer
   *  is_evaluated; // 0 if the question has not been evaluated, 1 if it has
   *  score; // The score the evaluator gave the user; this should be 0 if is_evaluated is 0.
   *  question_vid
   *  question_nid
   *  result_id
   */
  public function getReport() {

    // Basically, we encode internal information in a
    // legacy array format for Quiz.
    $report = array(
      'answer_id' => 0,
      // <-- Stupid vestige of multichoice.
      'answer' => $this->answer,
      'is_evaluated' => $this
        ->isEvaluated(),
      'is_correct' => $this
        ->isCorrect(),
      'score' => $this
        ->getScore(),
      'question_vid' => $this->question->vid,
      'question_nid' => $this->question->nid,
      'result_id' => $this->rid,
    );
    return $report;
  }

  /**
   * Creates the report form for the admin pages, and for when a user gets feedback after answering questions.
   *
   * The report is a form to allow editing scores and the likes while viewing the report form
   *
   * @param $showpoints
   * @param $showfeedback
   * @param $allow_scoring
   * @return $form
   *  Drupal form array
   */
  public function getReportForm($showpoints = TRUE, $showfeedback = TRUE, $allow_scoring = FALSE) {

    /*
     * Add general data, and data from the question type implementation
     */
    $form = array();
    $form['nid'] = array(
      '#type' => 'value',
      '#value' => $this->question->nid,
    );
    $form['vid'] = array(
      '#type' => 'value',
      '#value' => $this->question->vid,
    );
    $form['rid'] = array(
      '#type' => 'value',
      '#value' => $this->rid,
    );
    if ($submit = $this
      ->getReportFormSubmit($showpoints, $showfeedback, $allow_scoring)) {
      $form['submit'] = array(
        '#type' => 'value',
        '#value' => $submit,
      );
    }
    if ($validate = $this
      ->getReportFormValidate($showpoints, $showfeedback, $allow_scoring)) {
      $form['validate'] = array(
        '#type' => 'value',
        '#value' => $validate,
      );
    }
    $form['question'] = $this
      ->getReportFormQuestion($showpoints, $showfeedback);
    $form['score'] = $this
      ->getReportFormScore($showpoints, $showfeedback, $allow_scoring);
    $form['answer_feedback'] = $this
      ->getReportFormAnswerFeedback($showpoints, $showfeedback, $allow_scoring);
    $form['max_score'] = array(
      '#type' => 'value',
      '#value' => $this
        ->getMaxScore(),
    );
    $form['response'] = $this
      ->getReportFormResponse($showpoints, $showfeedback, $allow_scoring);
    $form['#theme'] = $this
      ->getReportFormTheme($showpoints, $showfeedback);
    $form['#is_correct'] = $this
      ->isCorrect();
    $form['#is_evaluated'] = $this
      ->isEvaluated();
    $form['#is_skipped'] = $this->is_skipped;
    $form['#is_doubtful'] = $this->is_doubtful;
    return $form;
  }

  /**
   * get the question part of the reportForm
   *
   * @param $showpoints
   * @param $showfeedback
   * @return
   *  FAPI form array holding the question
   */
  public function getReportFormQuestion($showpoints = TRUE, $showfeedback = TRUE) {
    $node = node_load($this->question->nid);
    $items = field_get_items('node', $node, 'body');
    return field_view_value('node', $node, 'body', $items[0]);
  }

  /**
   * Get the response part of the report form
   *
   * @param $showpoints
   * @param $showfeedback
   * @param $allow_scoring
   * @return
   *  FAPI form array holding the response part
   */
  public function getReportFormResponse($showpoints = TRUE, $showfeedback = TRUE, $allow_scoring = FALSE) {
    return array(
      '#markup' => '',
    );
  }

  /**
   * Get the score part of the report form
   *
   * @param $showpoints
   * @param $showfeedback
   * @param $allow_scoring
   * @return
   *  FAPI form array holding the score part
   */
  public function getReportFormScore($showpoints = TRUE, $showfeedback = TRUE, $allow_scoring = FALSE) {
    return array(
      '#markup' => '<span class="quiz-report-score">' . $this
        ->getScore() . '</span>',
    );
  }
  public function getReportFormAnswerFeedback($showpoints, $showfeedback, $allow_scoring) {
    return FALSE;
  }

  /**
   * Get the submit function for the reportForm
   *
   * @return
   *  Submit function as a string, or FALSE if no submit function
   */
  public function getReportFormSubmit($showfeedback = TRUE, $showpoints = TRUE, $allow_scoring = FALSE) {
    return FALSE;
  }

  /**
   * Get the validate function for the reportForm
   *
   * @return
   *  Validate function as a string, or FALSE if no validate function
   */
  public function getReportFormValidate($showfeedback = TRUE, $showpoints = TRUE, $allow_scoring = FALSE) {
    return FALSE;
  }

  /**
   * Get the theme key for the reportForm
   *
   * @return
   *  Theme key as a string, or FALSE if no submit function
   */
  public function getReportFormTheme($showfeedback = TRUE, $showpoints = TRUE) {
    return FALSE;
  }

  /**
   * Saves the quiz result. This is not used when a question is skipped!
   */
  public function saveResult() {
    $this->is_skipped = FALSE;
    $this
      ->save();
  }

  /**
   * Utility function that returns the format of the node body
   */
  protected function getFormat() {
    $body = field_get_items('node', $this->question, 'body');
    return $body ? $body[0]['format'] : NULL;
  }

  /**
   * Save the current response.
   */
  public abstract function save();

  /**
   * Delete the response.
   */
  public abstract function delete();

  /**
   * Calculate the score for the response.
   */
  public abstract function score();

  /**
   * Get the user's response.
   */
  public abstract function getResponse();

}

Members

Namesort descending Modifiers Type Description Overrides
QuizQuestionResponse::$answer protected property
QuizQuestionResponse::$evaluated protected property
QuizQuestionResponse::$is_correct protected property
QuizQuestionResponse::$is_doubtful public property
QuizQuestionResponse::$is_skipped public property
QuizQuestionResponse::$question public property
QuizQuestionResponse::$rid protected property
QuizQuestionResponse::$score protected property 1
QuizQuestionResponse::delete abstract public function Delete the response. 1
QuizQuestionResponse::getFormat protected function Utility function that returns the format of the node body
QuizQuestionResponse::getMaxScore public function Returns stored max score if it exists, if not the max score is calculated and returned.
QuizQuestionResponse::getParentQuiz public function Fetch the parent quiz.
QuizQuestionResponse::getReport public function Get data suitable for reporting a user's score on the question. This expects an object with the following attributes:
QuizQuestionResponse::getReportForm public function Creates the report form for the admin pages, and for when a user gets feedback after answering questions.
QuizQuestionResponse::getReportFormAnswerFeedback public function 1
QuizQuestionResponse::getReportFormQuestion public function get the question part of the reportForm
QuizQuestionResponse::getReportFormResponse public function Get the response part of the report form 1
QuizQuestionResponse::getReportFormScore public function Get the score part of the report form 1
QuizQuestionResponse::getReportFormSubmit public function Get the submit function for the reportForm 1
QuizQuestionResponse::getReportFormTheme public function Get the theme key for the reportForm
QuizQuestionResponse::getReportFormValidate public function Get the validate function for the reportForm 1
QuizQuestionResponse::getResponse abstract public function Get the user's response. 1
QuizQuestionResponse::getScore function Returns stored score if it exists, if not the score is calculated and returned.
QuizQuestionResponse::isCorrect function Check to see if the answer is marked as correct.
QuizQuestionResponse::isEvaluated public function Indicate whether the response has been evaluated (scored) yet. Questions that require human scoring (e.g. essays) may need to manually toggle this.
QuizQuestionResponse::isValid public function Validates response from a quiz taker. If the response isn't valid the quiz taker won't be allowed to proceed. 1
QuizQuestionResponse::quizContextAccessToScore public function Helper function to determine if a user has access to score a quiz.
QuizQuestionResponse::refreshQuestionNode public function Used to refresh this instances question node in case drupal has changed it.
QuizQuestionResponse::save abstract public function Save the current response. 1
QuizQuestionResponse::saveResult public function Saves the quiz result. This is not used when a question is skipped!
QuizQuestionResponse::score abstract public function Calculate the score for the response. 1
QuizQuestionResponse::toBareObject function Represent the response as a stdClass object.
QuizQuestionResponse::__construct public function Create a new user response. 1