Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/question/behaviour/behaviourbase.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 
00042 abstract class question_behaviour {
00054     const IS_ARCHETYPAL = false;
00055 
00057     protected $qa;
00059     protected $question;
00060 
00070     public function __construct(question_attempt $qa, $preferredbehaviour) {
00071         $this->qa = $qa;
00072         $this->question = $qa->get_question();
00073         if (!$this->is_compatible_question($this->question)) {
00074             throw new coding_exception('This behaviour (' . $this->get_name() .
00075                     ') cannot work with this question (' . get_class($this->question) . ')');
00076         }
00077     }
00078 
00088     public function is_compatible_question(question_definition $question) {
00089         $requiredclass = $this->required_question_definition_type();
00090         return $this->question instanceof $requiredclass;
00091     }
00092 
00103     protected function required_question_definition_type() {
00104         return 'question_definition';
00105     }
00106 
00111     public function get_name() {
00112         return substr(get_class($this), 11);
00113     }
00114 
00121     public static function get_unused_display_options() {
00122         return array();
00123     }
00124 
00136     public function render(question_display_options $options, $number,
00137             core_question_renderer $qoutput, qtype_renderer $qtoutput) {
00138         $behaviouroutput = $this->get_renderer($qoutput->get_page());
00139         $options = clone($options);
00140         $this->adjust_display_options($options);
00141         return $qoutput->question($this->qa, $behaviouroutput, $qtoutput, $options, $number);
00142     }
00143 
00153     public function check_file_access($options, $component, $filearea, $args, $forcedownload) {
00154         $this->adjust_display_options($options);
00155         return $this->question->check_file_access($this->qa, $options, $component,
00156                 $filearea, $args, $forcedownload);
00157     }
00158 
00163     public function get_renderer(moodle_page $page) {
00164         return $page->get_renderer(get_class($this));
00165     }
00166 
00175     public function adjust_display_options(question_display_options $options) {
00176         if (!$this->qa->has_marks()) {
00177             $options->correctness = false;
00178             $options->numpartscorrect = false;
00179         }
00180         if ($this->qa->get_state()->is_finished()) {
00181             $options->readonly = true;
00182             $options->numpartscorrect = $options->numpartscorrect &&
00183                     $this->qa->get_state()->is_partially_correct() &&
00184                     !empty($this->question->shownumcorrect);
00185         } else {
00186             $options->hide_all_feedback();
00187         }
00188     }
00189 
00194     public function get_applicable_hint() {
00195         return null;
00196     }
00197 
00206     public function get_min_fraction() {
00207         return 0;
00208     }
00209 
00217     public static function adjust_random_guess_score($fraction) {
00218         return $fraction;
00219     }
00220 
00227     public function get_expected_data() {
00228         if (!$this->qa->get_state()->is_finished()) {
00229             return array();
00230         }
00231 
00232         $vars = array('comment' => PARAM_RAW);
00233         if ($this->qa->get_max_mark()) {
00234             $vars['mark'] = question_attempt::PARAM_MARK;
00235             $vars['maxmark'] = PARAM_NUMBER;
00236         }
00237         return $vars;
00238     }
00239 
00251     public function get_expected_qt_data() {
00252         $fakeoptions = new question_display_options();
00253         $fakeoptions->readonly = false;
00254         $this->adjust_display_options($fakeoptions);
00255         if ($fakeoptions->readonly) {
00256             return array();
00257         } else {
00258             return $this->question->get_expected_data();
00259         }
00260     }
00261 
00267     public function get_correct_response() {
00268         return array();
00269     }
00270 
00283     public function get_question_summary() {
00284         return $this->question->get_question_summary();
00285     }
00286 
00295     public function get_right_answer_summary() {
00296         return null;
00297     }
00298 
00304     public function get_resume_data() {
00305         $olddata = $this->qa->get_step(0)->get_all_data();
00306         $olddata = $this->qa->get_last_qt_data() + $olddata;
00307         $olddata = $this->get_our_resume_data() + $olddata;
00308         return $olddata;
00309     }
00310 
00316     protected function get_our_resume_data() {
00317         return array();
00318     }
00319 
00328     public function classify_response() {
00329         return $this->question->classify_response($this->qa->get_last_qt_data());
00330     }
00331 
00340     public function get_state_string($showcorrectness) {
00341         return $this->qa->get_state()->default_string($showcorrectness);
00342     }
00343 
00344     public abstract function summarise_action(question_attempt_step $step);
00345 
00357     public function init_first_step(question_attempt_step $step, $variant) {
00358         $this->question->start_attempt($step, $variant);
00359     }
00360 
00368     protected function is_same_comment($pendingstep) {
00369         $previouscomment = $this->qa->get_last_behaviour_var('comment');
00370         $newcomment = $pendingstep->get_behaviour_var('comment');
00371 
00372         if (is_null($previouscomment) && !html_is_blank($newcomment) ||
00373                 $previouscomment != $newcomment) {
00374             return false;
00375         }
00376 
00377         // So, now we know the comment is the same, so check the mark, if present.
00378         $previousfraction = $this->qa->get_fraction();
00379         $newmark = $pendingstep->get_behaviour_var('mark');
00380 
00381         if (is_null($previousfraction)) {
00382             return is_null($newmark) || $newmark === '';
00383         } else if (is_null($newmark) || $newmark === '') {
00384             return false;
00385         }
00386 
00387         $newfraction = $newmark / $pendingstep->get_behaviour_var('maxmark');
00388 
00389         return abs($newfraction - $previousfraction) < 0.0000001;
00390     }
00391 
00436     public abstract function process_action(question_attempt_pending_step $pendingstep);
00437 
00445     public function process_comment(question_attempt_pending_step $pendingstep) {
00446         if (!$this->qa->get_state()->is_finished()) {
00447             throw new coding_exception('Cannot manually grade a question before it is finshed.');
00448         }
00449 
00450         if ($this->is_same_comment($pendingstep)) {
00451             return question_attempt::DISCARD;
00452         }
00453 
00454         if ($pendingstep->has_behaviour_var('mark')) {
00455             $fraction = $pendingstep->get_behaviour_var('mark') /
00456                             $pendingstep->get_behaviour_var('maxmark');
00457             if ($pendingstep->get_behaviour_var('mark') === '') {
00458                 $fraction = null;
00459             } else if ($fraction > 1 || $fraction < $this->qa->get_min_fraction()) {
00460                 throw new coding_exception('Score out of range when processing ' .
00461                         'a manual grading action.', $pendingstep);
00462             }
00463             $pendingstep->set_fraction($fraction);
00464         }
00465 
00466         $pendingstep->set_state($this->qa->get_state()->corresponding_commented_state(
00467                 $pendingstep->get_fraction()));
00468         return question_attempt::KEEP;
00469     }
00470 
00477     public function format_comment($comment = null, $commentformat = null) {
00478         $formatoptions = new stdClass();
00479         $formatoptions->noclean = true;
00480         $formatoptions->para = false;
00481 
00482         if (is_null($comment)) {
00483             list($comment, $commentformat) = $this->qa->get_manual_comment();
00484         }
00485 
00486         return format_text($comment, $commentformat, $formatoptions);
00487     }
00488 
00493     protected function summarise_manual_comment($step) {
00494         $a = new stdClass();
00495         if ($step->has_behaviour_var('comment')) {
00496             $a->comment = shorten_text(html_to_text($this->format_comment(
00497                     $step->get_behaviour_var('comment')), 0, false), 200);
00498         } else {
00499             $a->comment = '';
00500         }
00501 
00502         $mark = $step->get_behaviour_var('mark');
00503         if (is_null($mark) || $mark === '') {
00504             return get_string('commented', 'question', $a->comment);
00505         } else {
00506             $a->mark = $mark / $step->get_behaviour_var('maxmark') * $this->qa->get_max_mark();
00507             return get_string('manuallygraded', 'question', $a);
00508         }
00509     }
00510 
00511     public function summarise_start($step) {
00512         return get_string('started', 'question');
00513     }
00514 
00515     public function summarise_finish($step) {
00516         return get_string('attemptfinished', 'question');
00517     }
00518 }
00519 
00520 
00529 abstract class question_behaviour_with_save extends question_behaviour {
00530     public function required_question_definition_type() {
00531         return 'question_manually_gradable';
00532     }
00533 
00540     protected function is_same_response(question_attempt_step $pendingstep) {
00541         return $this->question->is_same_response(
00542                 $this->qa->get_last_step()->get_qt_data(), $pendingstep->get_qt_data());
00543     }
00544 
00554     protected function is_complete_response(question_attempt_step $pendingstep) {
00555         return $this->question->is_complete_response($pendingstep->get_qt_data());
00556     }
00557 
00565     public function process_save(question_attempt_pending_step $pendingstep) {
00566         if ($this->qa->get_state()->is_finished()) {
00567             return question_attempt::DISCARD;
00568         } else if (!$this->qa->get_state()->is_active()) {
00569             throw new coding_exception('Question is not active, cannot process_actions.');
00570         }
00571 
00572         if ($this->is_same_response($pendingstep)) {
00573             return question_attempt::DISCARD;
00574         }
00575 
00576         if ($this->is_complete_response($pendingstep)) {
00577             $pendingstep->set_state(question_state::$complete);
00578         } else {
00579             $pendingstep->set_state(question_state::$todo);
00580         }
00581         return question_attempt::KEEP;
00582     }
00583 
00584     public function summarise_submit(question_attempt_step $step) {
00585         return get_string('submitted', 'question',
00586                 $this->question->summarise_response($step->get_qt_data()));
00587     }
00588 
00589     public function summarise_save(question_attempt_step $step) {
00590         $data = $step->get_submitted_data();
00591         if (empty($data)) {
00592             return $this->summarise_start($step);
00593         }
00594         return get_string('saved', 'question',
00595                 $this->question->summarise_response($step->get_qt_data()));
00596     }
00597 
00598 
00599     public function summarise_finish($step) {
00600         $data = $step->get_qt_data();
00601         if ($data) {
00602             return get_string('attemptfinishedsubmitting', 'question',
00603                     $this->question->summarise_response($data));
00604         }
00605         return get_string('attemptfinished', 'question');
00606     }
00607 }
00608 
00609 
00617 abstract class question_cbm {
00619     const LOW = 1;
00620     const MED = 2;
00621     const HIGH = 3;
00625     public static $certainties = array(self::LOW, self::MED, self::HIGH);
00626 
00628     protected static $factor = array(
00629         self::LOW => 0.333333333333333,
00630         self::MED => 1.333333333333333,
00631         self::HIGH => 3,
00632     );
00633     protected static $offset = array(
00634         self::LOW => 0,
00635         self::MED => -0.666666666666667,
00636         self::HIGH => -2,
00637     );
00644     public static function default_certainty() {
00645         return self::LOW;
00646     }
00647 
00654     public static function adjust_fraction($fraction, $certainty) {
00655         return self::$offset[$certainty] + self::$factor[$certainty] * $fraction;
00656     }
00657 
00662     public static function get_string($certainty) {
00663         return get_string('certainty' . $certainty, 'qbehaviour_deferredcbm');
00664     }
00665 
00666     public static function summary_with_certainty($summary, $certainty) {
00667         if (is_null($certainty)) {
00668             return $summary;
00669         }
00670         return $summary . ' [' . self::get_string($certainty) . ']';
00671     }
00672 }
 All Data Structures Namespaces Files Functions Variables Enumerations