You are here

quizfileupload.classes.inc in Quiz File Upload 7.5

File upload question class.

This module uses the question interface to define the quizfileupload question type.

File

quizfileupload.classes.inc
View source
<?php

/**
 * @file
 * File upload question class.
 *
 * This module uses the question interface to define the quizfileupload question
 * type.
 */

/**
 * Extension of QuizQuestion.
 */
class QuizfileuploadQuestion extends QuizQuestion {

  // Constants for answer matching options.
  const ANSWER_MATCH = 0;
  const ANSWER_MANUAL = 1;

  /**
   * Implements saveNodeProperties().
   *
   * @see QuizQuestion#saveNodeProperties($is_new)
   */
  public function saveNodeProperties($is_new = FALSE) {
    db_merge('quiz_fileupload_node_properties')
      ->key(array(
      'nid' => $this->node->nid,
      'vid' => $this->node->vid,
    ))
      ->fields(array(
      'nid' => $this->node->nid,
      'vid' => $this->node->vid,
      'filetypes' => $this->node->filetypes,
      'filesize' => isset($this->node->filesize) ? $this->node->filesize : NULL,
      'correct_answer_evaluation' => $this->node->correct_answer_evaluation,
    ))
      ->execute();
  }

  /**
   * Implements validateNode().
   *
   * @see QuizQuestion#validateNode($form)
   */
  public function validateNode(array &$form) {

    // No validation required.
  }

  /**
   * Implements delete().
   *
   * @see QuizQuestion#delete($only_this_version)
   */
  public function delete($only_this_version = FALSE) {
    parent::delete($only_this_version);
    $delete_node = db_delete('quiz_fileupload_node_properties');
    $delete_node
      ->condition('nid', $this->node->nid);
    if ($only_this_version) {
      $delete_node
        ->condition('vid', $this->node->vid);
    }
    $delete_node
      ->execute();
  }

  /**
   * Implements getNodeProperties().
   *
   * @see QuizQuestion#getNodeProperties()
   */
  public function getNodeProperties() {
    if (isset($this->nodeProperties)) {
      return $this->nodeProperties;
    }
    $props = parent::getNodeProperties();

    // Load the properties.
    $result = db_select('quiz_fileupload_node_properties', 'qfnp')
      ->fields('qfnp', array(
      'filetypes',
      'correct_answer_evaluation',
    ))
      ->fields('qfnp', array(
      'filetypes',
      'filesize',
      'correct_answer_evaluation',
    ))
      ->condition('nid', $this->node->nid, '=')
      ->condition('vid', $this->node->vid, '=')
      ->execute()
      ->fetchAssoc();
    $this->nodeProperties = is_array($result) ? array_merge($props, $result) : $props;
    return $this->nodeProperties;
  }

  /**
   * Implements getNodeView().
   *
   * @see QuizQuestion#getNodeView()
   */
  public function getNodeView() {
    $content = parent::getNodeView();

    // No need to really check permissions as we actually don't show any answer
    // here.
    $content['answers'] = array(
      '#markup' => '<div class="quiz-solution">' . check_plain($this->node->filetypes) . '</div>',
      '#weight' => 2,
    );
    return $content;
  }

  /**
   * Implements getAnsweringForm().
   *
   * @see QuizQuestion#getAnsweringForm($form_state, $result_id)
   */
  public function getAnsweringForm(array $form_state = NULL, $result_id) {
    $element = parent::getAnsweringForm($form_state, $result_id);
    $filesize = !empty($this->node->filesize) ? parse_size($this->node->filesize) : file_upload_max_size();
    $description = array(
      t('Files must be less than !size.', array(
        '!size' => '<strong>' . format_size($filesize) . '</strong>',
      )),
      t('Allowed file types: !extensions.', array(
        '!extensions' => '<strong>' . check_plain($this->node->filetypes) . '</strong>',
      )),
    );
    $element += array(
      '#type' => 'managed_file',
      '#title' => t('Upload'),
      '#description' => implode('<br />', $description),
      '#required' => FALSE,
      '#upload_location' => variable_get('quizfileupload_upload_location', 'public') . '://quizfileupload/' . $this->node->nid . '/',
      '#upload_validators' => array(
        'file_validate_extensions' => array(
          $this->node->filetypes,
        ),
        'file_validate_size' => array(
          parse_size($filesize),
        ),
      ),
    );
    if (isset($result_id)) {
      $response = new QuizfileuploadResponse($result_id, $this->node);
      $element['#default_value'] = $response
        ->getResponse();
    }
    return $element;
  }

  /**
   * Question response validator.
   */
  public function getAnsweringFormValidate(array &$element, &$value) {
    if (empty($value['fid'])) {
      form_set_error($element['#name'], t('You must upload a file.'));
    }
    else {

      // If we have a file we'll set the status to permanent.
      // We mainly do it here so that the "allow resume" function of the quiz
      // should work as expected for the file upload as well.
      $file = file_load($value['fid']);
      $file->status = FILE_STATUS_PERMANENT;
      file_save($file);
    }
  }

  /**
   * Implements getCreationForm().
   *
   * @see QuizQuestion#getCreationForm()
   */
  public function getCreationForm(array &$form_state = NULL) {
    $allowed = variable_get('quizfileupload_default_extensions', QUIZFILEUPLOAD_DEFAULT_EXTENSIONS);
    $form['filetypes'] = array(
      '#type' => 'textfield',
      '#title' => t('Allowed file extensions'),
      '#description' => t('Separate extensions with a space or comma and do not include the leading dot.'),
      '#default_value' => str_replace(' ', ', ', isset($this->node->filetypes) ? $this->node->filetypes : $allowed),
      '#element_validate' => array(
        '_file_generic_settings_extensions',
      ),
      '#required' => TRUE,
    );
    $form['filesize'] = array(
      '#type' => 'textfield',
      '#title' => t('Maximum upload size'),
      '#default_value' => isset($this->node->filesize) ? $this->node->filesize : variable_get('quizfileupload_default_filesize', NULL),
      '#description' => t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current limit <strong>%limit</strong>).', array(
        '%limit' => format_size(file_upload_max_size()),
      )),
      '#maxlength' => 18,
      '#element_validate' => array(
        '_file_generic_settings_max_filesize',
      ),
    );
    $options = array(
      self::ANSWER_MATCH => t('Automatic'),
      self::ANSWER_MANUAL => t('Manual'),
    );
    $form['correct_answer_evaluation'] = array(
      '#type' => 'radios',
      '#title' => t('Pick an evaluation method'),
      '#description' => t('Choose how the answer shall be evaluated.'),
      '#options' => $options,
      '#default_value' => isset($this->node->correct_answer_evaluation) ? $this->node->correct_answer_evaluation : self::ANSWER_MATCH,
      '#required' => TRUE,
    );
    return $form;
  }

  /**
   * Implements getMaximumScore().
   *
   * @see QuizQuestion#getMaximumScore()
   */
  public function getMaximumScore() {
    return variable_get('quizfileupload_default_score', 1);
  }

}

/**
 * Extension of QuizQuestionResponse.
 */
class QuizfileuploadResponse extends QuizQuestionResponse {

  // ID of the answer.
  protected $answer_id = 0;
  protected $fid = NULL;
  private $answer_feedback;
  private $answer_feedback_format;

  /**
   * Constructor.
   */
  public function __construct($result_id, stdClass $question_node, $answer = NULL) {
    parent::__construct($result_id, $question_node, $answer);
    if (!isset($answer)) {
      $r = db_select('quiz_fileupload_user_answers', 'qfua')
        ->fields('qfua', array(
        'fid',
        'score',
        'is_evaluated',
        'answer_id',
        'answer_feedback',
        'answer_feedback_format',
      ))
        ->condition('result_answer_id', $this->result_answer_id, '=')
        ->execute()
        ->fetchObject();
      if (!empty($r)) {
        $this->answer = $r->fid;
        $this->score = $r->score;
        $this->evaluated = $r->is_evaluated;
        $this->answer_id = $r->answer_id;
        $this->answer_feedback = $r->answer_feedback;
        $this->answer_feedback_format = $r->answer_feedback_format;
      }
    }
    else {
      if (is_array($answer)) {
        $this->answer = $answer['fid'];
      }
      else {
        $this->answer = $answer;
      }
    }
  }

  /**
   * Implements save().
   *
   * @see QuizQuestionResponse#save()
   */
  public function save() {

    // Check if we need to manually evaluate this.
    $this->is_evaluated = isset($this->question->correct_answer_evaluation) && $this->question->correct_answer_evaluation == 1 ? 0 : 1;
    db_merge('quiz_fileupload_user_answers')
      ->key(array(
      'result_answer_id' => $this->result_answer_id,
    ))
      ->fields(array(
      'fid' => $this->answer,
      'result_answer_id' => $this->result_answer_id,
      'score' => $this
        ->getScore(FALSE),
      'is_evaluated' => $this->is_evaluated,
    ))
      ->execute();
  }

  /**
   * Implements delete().
   *
   * @see QuizQuestionResponse#delete()
   */
  public function delete() {
    db_delete('quiz_fileupload_user_answers')
      ->condition('result_answer_id', $this->result_answer_id)
      ->execute();
  }

  /**
   * Implements score().
   *
   * @see QuizQuestionResponse#score()
   */
  public function score() {
    $score = 0;
    if (isset($this->result_answer_id)) {

      // Manual scoring means we go with what is in the DB.
      if (isset($this->question->correct_answer_evaluation) && $this->question->correct_answer_evaluation == 1) {
        $score = db_select('quiz_fileupload_user_answers', 'qfua')
          ->fields('qfua', array(
          'score',
        ))
          ->condition('result_answer_id', $this->result_answer_id, '=')
          ->execute()
          ->fetchField();
        if (!$score) {
          $score = 0;
        }
      }
      else {
        $fileuploadAnswer = new QuizfileuploadQuestion($this->question);
        $score = $fileuploadAnswer
          ->getMaximumScore();
      }
    }
    return $score;
  }

  /**
   * Implements getResponse().
   *
   * @see QuizQuestionResponse#getResponse()
   */
  public function getResponse() {
    return $this->answer;
  }

  /**
   * Implements getFeedbackValues().
   */
  public function getFeedbackValues() {
    $data = array();

    // Hide the columns 'choice' and 'solution' as neither are really relevant
    // for a fileupload question.
    $data[] = array(
      'choice' => NULL,
      'attempt' => quiz_file_markup($this->answer),
      'correct' => $this->question->answers[0]['is_correct'] ? quiz_icon('correct') : quiz_icon(''),
      'score' => !$this->evaluated ? t('This answer has not yet been scored.') : $this
        ->getScore(),
      'answer_feedback' => check_markup($this->answer_feedback, $this->answer_feedback_format),
      'solution' => NULL,
    );
    return $data;
  }

  /**
   * Implements getReportFormAnswerFeedback().
   */
  public function getReportFormAnswerFeedback() {
    return array(
      '#title' => t('Enter feedback'),
      '#type' => 'text_format',
      '#default_value' => $this->answer_feedback,
      '#format' => isset($this->answer_feedback_format) ? $this->answer_feedback_format : filter_default_format(),
      '#attributes' => array(
        'class' => array(
          'quiz-report-score',
        ),
      ),
    );
  }

  /**
   * Implements getReportFormSubmit().
   *
   * @see QuizQuestionResponse#getReportFormSubmit()
   */
  public function getReportFormSubmit() {
    return 'quizfileupload_report_submit';
  }

}

Classes

Namesort descending Description
QuizfileuploadQuestion Extension of QuizQuestion.
QuizfileuploadResponse Extension of QuizQuestionResponse.