Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/question/type/questionbase.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 
00041 abstract class question_definition {
00044     public $id;
00045 
00047     public $category;
00048 
00050     public $contextid;
00051 
00053     public $parent = 0;
00054 
00056     public $qtype;
00057 
00059     public $name;
00060 
00062     public $questiontext;
00063 
00065     public $questiontextformat;
00066 
00068     public $generalfeedback;
00069 
00071     public $generalfeedbackformat;
00072 
00074     public $defaultmark = 1;
00075 
00077     public $length = 1;
00078 
00080     public $penalty = 0;
00081 
00083     public $stamp;
00084 
00086     public $version;
00087 
00089     public $hidden = 0;
00090 
00092     public $timecreated;
00093 
00095     public $timemodified;
00096 
00098     public $createdby;
00099 
00101     public $modifiedby;
00102 
00104     public $hints = array();
00105 
00112     public function __construct() {
00113     }
00114 
00119     public function get_type_name() {
00120         return $this->qtype->name();
00121     }
00122 
00143     public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
00144         return question_engine::make_archetypal_behaviour($preferredbehaviour, $qa);
00145     }
00146 
00163     public function start_attempt(question_attempt_step $step, $variant) {
00164     }
00165 
00179     public function apply_attempt_state(question_attempt_step $step) {
00180     }
00181 
00191     public function get_question_summary() {
00192         return $this->html_to_text($this->questiontext, $this->questiontextformat);
00193     }
00194 
00198     public function get_num_variants() {
00199         return 1;
00200     }
00201 
00206     public function get_variants_selection_seed() {
00207         return $this->stamp;
00208     }
00209 
00218     public function get_min_fraction() {
00219         return 0;
00220     }
00221 
00227     public function clear_wrong_from_response(array $response) {
00228         return array();
00229     }
00230 
00237     public function get_num_parts_right(array $response) {
00238         return array(null, null);
00239     }
00240 
00245     public function get_renderer(moodle_page $page) {
00246         return $page->get_renderer($this->qtype->plugin_name());
00247     }
00248 
00260     public abstract function get_expected_data();
00261 
00270     public abstract function get_correct_response();
00271 
00285     public function format_text($text, $format, $qa, $component, $filearea, $itemid,
00286             $clean = false) {
00287         $formatoptions = new stdClass();
00288         $formatoptions->noclean = !$clean;
00289         $formatoptions->para = false;
00290         $text = $qa->rewrite_pluginfile_urls($text, $component, $filearea, $itemid);
00291         return format_text($text, $format, $formatoptions);
00292     }
00293 
00301     public function html_to_text($text, $format) {
00302         return html_to_text(format_text($text, $format, array('noclean' => true)), 0, false);
00303     }
00304 
00306     public function format_questiontext($qa) {
00307         return $this->format_text($this->questiontext, $this->questiontextformat,
00308                 $qa, 'question', 'questiontext', $this->id);
00309     }
00310 
00312     public function format_generalfeedback($qa) {
00313         return $this->format_text($this->generalfeedback, $this->generalfeedbackformat,
00314                 $qa, 'question', 'generalfeedback', $this->id);
00315     }
00316 
00327     public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) {
00328         if ($component == 'question' && $filearea == 'questiontext') {
00329             // Question text always visible.
00330             return true;
00331 
00332         } else if ($component == 'question' && $filearea == 'generalfeedback') {
00333             return $options->generalfeedback;
00334 
00335         } else {
00336             // Unrecognised component or filearea.
00337             return false;
00338         }
00339     }
00340 }
00341 
00342 
00350 class question_information_item extends question_definition {
00351     public function __construct() {
00352         parent::__construct();
00353         $this->defaultmark = 0;
00354         $this->penalty = 0;
00355         $this->length = 0;
00356     }
00357 
00358     public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
00359         question_engine::load_behaviour_class('informationitem');
00360         return new qbehaviour_informationitem($qa, $preferredbehaviour);
00361     }
00362 
00363     public function get_expected_data() {
00364         return array();
00365     }
00366 
00367     public function get_correct_response() {
00368         return array();
00369     }
00370 
00371     public function get_question_summary() {
00372         return null;
00373     }
00374 }
00375 
00376 
00384 interface question_manually_gradable {
00394     public function is_complete_response(array $response);
00395 
00407     public function is_same_response(array $prevresponse, array $newresponse);
00408 
00414     public function summarise_response(array $response);
00415 
00423     public function classify_response(array $response);
00424 }
00425 
00426 
00434 class question_classified_response {
00440     public $responseclassid;
00442     public $response;
00444     public $fraction;
00451     public function __construct($responseclassid, $response, $fraction) {
00452         $this->responseclassid = $responseclassid;
00453         $this->response = $response;
00454         $this->fraction = $fraction;
00455     }
00456 
00457     public static function no_response() {
00458         return new question_classified_response(null, get_string('noresponse', 'question'), null);
00459     }
00460 }
00461 
00462 
00470 interface question_automatically_gradable extends question_manually_gradable {
00480     public function is_gradable_response(array $response);
00481 
00487     public function get_validation_error(array $response);
00488 
00497     public function grade_response(array $response);
00498 
00507     public function get_hint($hintnumber, question_attempt $qa);
00508 
00516     public function get_right_answer_summary();
00517 }
00518 
00519 
00527 interface question_automatically_gradable_with_countback extends question_automatically_gradable {
00538     public function compute_final_grade($responses, $totaltries);
00539 }
00540 
00541 
00549 abstract class question_with_responses extends question_definition
00550         implements question_manually_gradable {
00551     public function classify_response(array $response) {
00552         return array();
00553     }
00554 }
00555 
00556 
00563 abstract class question_graded_automatically extends question_with_responses
00564         implements question_automatically_gradable {
00566     public $shownumcorrect = false;
00567 
00568     public function is_gradable_response(array $response) {
00569         return $this->is_complete_response($response);
00570     }
00571 
00572     public function get_right_answer_summary() {
00573         $correctresponse = $this->get_correct_response();
00574         if (empty($correctresponse)) {
00575             return null;
00576         }
00577         return $this->summarise_response($correctresponse);
00578     }
00579 
00587     protected function check_combined_feedback_file_access($qa, $options, $filearea) {
00588         $state = $qa->get_state();
00589 
00590         if (!$state->is_finished()) {
00591             $response = $qa->get_last_qt_data();
00592             if (!$this->is_gradable_response($response)) {
00593                 return false;
00594             }
00595             list($notused, $state) = $this->grade_response($response);
00596         }
00597 
00598         return $options->feedback && $state->get_feedback_class() . 'feedback' == $filearea;
00599     }
00600 
00608     protected function check_hint_file_access($qa, $options, $args) {
00609         if (!$options->feedback) {
00610             return false;
00611         }
00612         $hint = $qa->get_applicable_hint();
00613         $hintid = reset($args); // itemid is hint id.
00614         return $hintid == $hint->id;
00615     }
00616 
00617     public function get_hint($hintnumber, question_attempt $qa) {
00618         if (!isset($this->hints[$hintnumber])) {
00619             return null;
00620         }
00621         return $this->hints[$hintnumber];
00622     }
00623 
00624     public function format_hint(question_hint $hint, question_attempt $qa) {
00625         return $this->format_text($hint->hint, $hint->hintformat, $qa,
00626                 'question', 'hint', $hint->id);
00627     }
00628 }
00629 
00630 
00638 abstract class question_graded_automatically_with_countback
00639         extends question_graded_automatically
00640         implements question_automatically_gradable_with_countback {
00641 
00642     public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
00643         if ($preferredbehaviour == 'interactive') {
00644             return question_engine::make_behaviour('interactivecountback',
00645                     $qa, $preferredbehaviour);
00646         }
00647         return question_engine::make_archetypal_behaviour($preferredbehaviour, $qa);
00648     }
00649 }
00650 
00651 
00659 abstract class question_graded_by_strategy extends question_graded_automatically {
00661     protected $gradingstrategy;
00662 
00664     public function __construct(question_grading_strategy $strategy) {
00665         parent::__construct();
00666         $this->gradingstrategy = $strategy;
00667     }
00668 
00669     public function get_correct_response() {
00670         $answer = $this->get_correct_answer();
00671         if (!$answer) {
00672             return array();
00673         }
00674 
00675         return array('answer' => $answer->answer);
00676     }
00677 
00684     public function get_matching_answer(array $response) {
00685         return $this->gradingstrategy->grade($response);
00686     }
00687 
00692     public function get_correct_answer() {
00693         return $this->gradingstrategy->get_correct_answer();
00694     }
00695 
00696     public function grade_response(array $response) {
00697         $answer = $this->get_matching_answer($response);
00698         if ($answer) {
00699             return array($answer->fraction,
00700                     question_state::graded_state_for_fraction($answer->fraction));
00701         } else {
00702             return array(0, question_state::$gradedwrong);
00703         }
00704     }
00705 
00706     public function classify_response(array $response) {
00707         if (empty($response['answer'])) {
00708             return array($this->id => question_classified_response::no_response());
00709         }
00710 
00711         $ans = $this->get_matching_answer($response);
00712         if (!$ans) {
00713             return array($this->id => new question_classified_response(
00714                     0, $response['answer'], 0));
00715         }
00716 
00717         return array($this->id => new question_classified_response(
00718                 $ans->id, $response['answer'], $ans->fraction));
00719     }
00720 }
00721 
00722 
00730 class question_answer {
00732     public $id;
00733 
00735     public $answer;
00736 
00738     public $answerformat = FORMAT_PLAIN;
00739 
00741     public $fraction;
00742 
00744     public $feedback;
00745 
00747     public $feedbackformat;
00748 
00758     public function __construct($id, $answer, $fraction, $feedback, $feedbackformat) {
00759         $this->id = $id;
00760         $this->answer = $answer;
00761         $this->fraction = $fraction;
00762         $this->feedback = $feedback;
00763         $this->feedbackformat = $feedbackformat;
00764     }
00765 }
00766 
00767 
00775 class question_hint {
00777     public $id;
00779     public $hint;
00781     public $hintformat;
00782 
00789     public function __construct($id, $hint, $hintformat) {
00790         $this->id = $id;
00791         $this->hint = $hint;
00792         $this->hintformat = $hintformat;
00793     }
00794 
00800     public static function load_from_record($row) {
00801         return new question_hint($row->id, $row->hint, $row->hintformat);
00802     }
00803 
00808     public function adjust_display_options(question_display_options $options) {
00809         // Do nothing.
00810     }
00811 }
00812 
00813 
00822 class question_hint_with_parts extends question_hint {
00824     public $shownumcorrect;
00825 
00827     public $clearwrong;
00828 
00837     public function __construct($id, $hint, $hintformat, $shownumcorrect, $clearwrong) {
00838         parent::__construct($id, $hint, $hintformat);
00839         $this->shownumcorrect = $shownumcorrect;
00840         $this->clearwrong = $clearwrong;
00841     }
00842 
00848     public static function load_from_record($row) {
00849         return new question_hint_with_parts($row->id, $row->hint, $row->hintformat,
00850                 $row->shownumcorrect, $row->clearwrong);
00851     }
00852 
00853     public function adjust_display_options(question_display_options $options) {
00854         parent::adjust_display_options($options);
00855         if ($this->clearwrong) {
00856             $options->clearwrong = true;
00857         }
00858         $options->numpartscorrect = $this->shownumcorrect;
00859     }
00860 }
00861 
00862 
00870 interface question_grading_strategy {
00877     public function grade(array $response);
00878 
00883     public function get_correct_answer();
00884 }
00885 
00886 
00895 interface question_response_answer_comparer {
00897     public function get_answers();
00898 
00904     public function compare_response_with_answer(array $response, question_answer $answer);
00905 }
00906 
00907 
00917 class question_first_matching_answer_grading_strategy implements question_grading_strategy {
00922     protected $question;
00923 
00928     public function __construct(question_response_answer_comparer $question) {
00929         $this->question = $question;
00930     }
00931 
00932     public function grade(array $response) {
00933         foreach ($this->question->get_answers() as $aid => $answer) {
00934             if ($this->question->compare_response_with_answer($response, $answer)) {
00935                 $answer->id = $aid;
00936                 return $answer;
00937             }
00938         }
00939         return null;
00940     }
00941 
00942     public function get_correct_answer() {
00943         foreach ($this->question->get_answers() as $answer) {
00944             $state = question_state::graded_state_for_fraction($answer->fraction);
00945             if ($state == question_state::$gradedright) {
00946                 return $answer;
00947             }
00948         }
00949         return null;
00950     }
00951 }
 All Data Structures Namespaces Files Functions Variables Enumerations