questiontype.php

来自「很棒的在线教学系统」· PHP 代码 · 共 723 行 · 第 1/2 页

PHP
723
字号
<?php  // $Id: questiontype.php,v 1.32.2.11 2009/01/23 02:19:36 tjhunt Exp $//////////////// MATCH /////////////////// QUESTION TYPE CLASS ///////////////////** * @package questionbank * @subpackage questiontypes */class question_match_qtype extends default_questiontype {    function name() {        return 'match';    }    function get_question_options(&$question) {        $question->options = get_record('question_match', 'question', $question->id);        $question->options->subquestions = get_records('question_match_sub', 'question', $question->id, 'id ASC');        return true;    }    function save_question_options($question) {        $result = new stdClass;        if (!$oldsubquestions = get_records("question_match_sub", "question", $question->id, "id ASC")) {            $oldsubquestions = array();        }        // $subquestions will be an array with subquestion ids        $subquestions = array();        // Insert all the new question+answer pairs        foreach ($question->subquestions as $key => $questiontext) {            $questiontext = trim($questiontext);            $answertext = trim($question->subanswers[$key]);            if ($questiontext != '' || $answertext != '') {                if ($subquestion = array_shift($oldsubquestions)) {  // Existing answer, so reuse it                    $subquestion->questiontext = $questiontext;                    $subquestion->answertext   = $answertext;                    if (!update_record("question_match_sub", $subquestion)) {                        $result->error = "Could not insert match subquestion! (id=$subquestion->id)";                        return $result;                    }                } else {                    $subquestion = new stdClass;                    // Determine a unique random code                    $subquestion->code = rand(1,999999999);                    while (record_exists('question_match_sub', 'code', $subquestion->code, 'question', $question->id)) {                        $subquestion->code = rand();                    }                    $subquestion->question = $question->id;                    $subquestion->questiontext = $questiontext;                    $subquestion->answertext   = $answertext;                    if (!$subquestion->id = insert_record("question_match_sub", $subquestion)) {                        $result->error = "Could not insert match subquestion!";                        return $result;                    }                }                $subquestions[] = $subquestion->id;            }            if ($questiontext != '' && $answertext == '') {                $result->notice = get_string('nomatchinganswer', 'quiz', $questiontext);            }        }        // delete old subquestions records        if (!empty($oldsubquestions)) {            foreach($oldsubquestions as $os) {                delete_records('question_match_sub', 'id', $os->id);            }        }        if ($options = get_record("question_match", "question", $question->id)) {            $options->subquestions = implode(",",$subquestions);            $options->shuffleanswers = $question->shuffleanswers;            if (!update_record("question_match", $options)) {                $result->error = "Could not update match options! (id=$options->id)";                return $result;            }        } else {            unset($options);            $options->question = $question->id;            $options->subquestions = implode(",",$subquestions);            $options->shuffleanswers = $question->shuffleanswers;            if (!insert_record("question_match", $options)) {                $result->error = "Could not insert match options!";                return $result;            }        }        if (!empty($result->notice)) {            return $result;        }        if (count($subquestions) < 3) {            $result->notice = get_string('notenoughanswers', 'quiz', 3);            return $result;        }        return true;    }    /**    * Deletes question from the question-type specific tables    *    * @return boolean Success/Failure    * @param integer $question->id    */    function delete_question($questionid) {        delete_records("question_match", "question", $questionid);        delete_records("question_match_sub", "question", $questionid);        return true;    }    function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {        if (!$state->options->subquestions = get_records('question_match_sub', 'question', $question->id, 'id ASC')) {            notify('Error: Missing subquestions!');            return false;        }        foreach ($state->options->subquestions as $key => $subquestion) {            // This seems rather over complicated, but it is useful for the            // randomsamatch questiontype, which can then inherit the print            // and grading functions. This way it is possible to define multiple            // answers per question, each with different marks and feedback.            $answer = new stdClass();            $answer->id       = $subquestion->code;            $answer->answer   = $subquestion->answertext;            $answer->fraction = 1.0;            $state->options->subquestions[$key]->options->answers[$subquestion->code] = clone($answer);            $state->responses[$key] = '';        }        // Shuffle the answers if required        if ($cmoptions->shuffleanswers and $question->options->shuffleanswers) {           $state->options->subquestions = swapshuffle_assoc($state->options->subquestions);        }        return true;    }    function restore_session_and_responses(&$question, &$state) {        // The serialized format for matching questions is a comma separated        // list of question answer pairs (e.g. 1-1,2-3,3-2), where the ids of        // both refer to the id in the table question_match_sub.        $responses = explode(',', $state->responses['']);        $responses = array_map(create_function('$val', 'return explode("-", $val);'), $responses);        if (!$questions = get_records('question_match_sub', 'question', $question->id, 'id ASC')) {           notify('Error: Missing subquestions!');           return false;        }        // Restore the previous responses and place the questions into the state options        $state->responses = array();        $state->options->subquestions = array();        foreach ($responses as $response) {            $state->responses[$response[0]] = $response[1];            $state->options->subquestions[$response[0]] = $questions[$response[0]];        }        foreach ($state->options->subquestions as $key => $subquestion) {            // This seems rather over complicated, but it is useful for the            // randomsamatch questiontype, which can then inherit the print            // and grading functions. This way it is possible to define multiple            // answers per question, each with different marks and feedback.            $answer = new stdClass();            $answer->id       = $subquestion->code;            $answer->answer   = $subquestion->answertext;            $answer->fraction = 1.0;            $state->options->subquestions[$key]->options->answers[$subquestion->code] = clone($answer);        }        return true;    }    function save_session_and_responses(&$question, &$state) {         $subquestions = &$state->options->subquestions;        // Prepare an array to help when disambiguating equal answers.        $answertexts = array();        foreach ($subquestions as $subquestion) {            $ans = reset($subquestion->options->answers);            $answertexts[$ans->id] = $ans->answer;        }        // Serialize responses        $responses = array();        foreach ($subquestions as $key => $subquestion) {            $response = 0;            if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {                if ($state->responses[$key]) {                    $response = $state->responses[$key];                    if (!array_key_exists($response, $subquestion->options->answers)) {                        // If student's answer did not match by id, but there may be                        // two answers with the same text, but different ids,                        // so we need to try matching the answer text.                        $expected_answer = reset($subquestion->options->answers);                        if ($answertexts[$response] == $expected_answer->answer) {                            $response = $expected_answer->id;                            $state->responses[$key] = $response;                        }                    }                }            }            $responses[] = $key.'-'.$response;        }        $responses = implode(',', $responses);        // Set the legacy answer field        if (!set_field('question_states', 'answer', $responses, 'id', $state->id)) {            return false;        }        return true;    }    function get_correct_responses(&$question, &$state) {        $responses = array();        foreach ($state->options->subquestions as $sub) {            foreach ($sub->options->answers as $answer) {                if (1 == $answer->fraction && $sub->questiontext != '' && !is_null($sub->questiontext)) {                    $responses[$sub->id] = $answer->id;                }            }        }        return empty($responses) ? null : $responses;    }    function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {        global $CFG;        $subquestions   = $state->options->subquestions;        $correctanswers = $this->get_correct_responses($question, $state);        $nameprefix     = $question->name_prefix;        $answers        = array(); // Answer choices formatted ready for output.        $allanswers     = array(); // This and the next used to detect identical answers        $answerids      = array(); // and adjust ids.        $responses      = &$state->responses;        // Prepare a list of answers, removing duplicates.        foreach ($subquestions as $subquestion) {            foreach ($subquestion->options->answers as $ans) {                $allanswers[$ans->id] = $ans->answer;                if (!in_array($ans->answer, $answers)) {                    $answers[$ans->id] = strip_tags(format_string($ans->answer, false));                    $answerids[$ans->answer] = $ans->id;                }            }        }        // Fix up the ids of any responses that point the the eliminated duplicates.        foreach ($responses as $subquestionid => $ignored) {            if ($responses[$subquestionid]) {                $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]];            }        }        foreach ($correctanswers as $subquestionid => $ignored) {            $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]];        }        // Shuffle the answers        $answers = draw_rand_array($answers, count($answers));        // Print formulation        $questiontext = $this->format_text($question->questiontext,                $question->questiontextformat, $cmoptions);        $image = get_question_image($question);        // Print the input controls        foreach ($subquestions as $key => $subquestion) {            if ($subquestion->questiontext !== '' && !is_null($subquestion->questiontext)) {                // Subquestion text:                $a = new stdClass;                $a->text = $this->format_text($subquestion->questiontext,                        $question->questiontextformat, $cmoptions);                // Drop-down list:                $menuname = $nameprefix.$subquestion->id;                $response = isset($state->responses[$subquestion->id])                            ? $state->responses[$subquestion->id] : '0';                $a->class = ' ';                $a->feedbackimg = ' ';                if ($options->readonly and $options->correct_responses) {                    if (isset($correctanswers[$subquestion->id])                            and ($correctanswers[$subquestion->id] == $response)) {                        $correctresponse = 1;                    } else {                        $correctresponse = 0;                    }                    if ($options->feedback && $response) {                        $a->class = question_get_feedback_class($correctresponse);                        $a->feedbackimg = question_get_feedback_image($correctresponse);                    }                }                $a->control = choose_from_menu($answers, $menuname, $response, 'choose',                                               '', 0, true, $options->readonly);                // Neither the editing interface or the database allow to provide                // fedback for this question type.                // However (as was pointed out in bug bug 3294) the randomsamatch                // type which reuses this method can have feedback defined for                // the wrapped shortanswer questions.                //if ($options->feedback                // && !empty($subquestion->options->answers[$responses[$key]]->feedback)) {                //    print_comment($subquestion->options->answers[$responses[$key]]->feedback);                //}                $anss[] = $a;            }        }        include("$CFG->dirroot/question/type/match/display.html");    }    function grade_responses(&$question, &$state, $cmoptions) {        $subquestions = &$state->options->subquestions;        $responses    = &$state->responses;        // Prepare an array to help when disambiguating equal answers.        $answertexts = array();        foreach ($subquestions as $subquestion) {            $ans = reset($subquestion->options->answers);            $answertexts[$ans->id] = $ans->answer;        }        // Add up the grades from each subquestion.        $sumgrade = 0;        $totalgrade = 0;        foreach ($subquestions as $key => $sub) {            if ($sub->questiontext !== '' && !is_null($sub->questiontext)) {                $totalgrade += 1;                $response = $responses[$key];                if ($response && !array_key_exists($response, $sub->options->answers)) {                    // If studen's answer did not match by id, but there may be                    // two answers with the same text, but different ids,                    // so we need to try matching the answer text.                    $expected_answer = reset($sub->options->answers);                    if ($answertexts[$response] == $expected_answer->answer) {                        $response = $expected_answer->id;                    }                }                if (array_key_exists($response, $sub->options->answers)) {                    $sumgrade += $sub->options->answers[$response]->fraction;                }            }        }        $state->raw_grade = $sumgrade/$totalgrade;        if (empty($state->raw_grade)) {            $state->raw_grade = 0;        }        // Make sure we don't assign negative or too high marks        $state->raw_grade = min(max((float) $state->raw_grade,                            0.0), 1.0) * $question->maxgrade;        $state->penalty = $question->penalty * $question->maxgrade;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?