From: tjhunt Date: Fri, 28 Nov 2008 06:07:11 +0000 (+0000) Subject: random essay questions: MDL-8648 Allow essay questions to be selected by random question. X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=f24493ec9b0e46c30c5343283dd10179a0fd892e;p=moodle.git random essay questions: MDL-8648 Allow essay questions to be selected by random question. In the 1.9 branch this is controlled by a new option under Admin -> Experimental. In Moodle 2.0 dev it is not optional, it just works. The main change is letting the manual grading report know which random questions might need manual grading. MDL-4004 - this depends on the random question under consideration, which requires a new questiontype method. I also changed the random question code so that I could remove some global variables. --- diff --git a/lang/en_utf8/qtype_random.php b/lang/en_utf8/qtype_random.php new file mode 100644 index 0000000000..8fec9a9dd1 --- /dev/null +++ b/lang/en_utf8/qtype_random.php @@ -0,0 +1,4 @@ + diff --git a/lib/questionlib.php b/lib/questionlib.php index 225ea880b0..10ad27e712 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -119,19 +119,13 @@ define('QUESTION_FLAGSSHOWN', 1); define('QUESTION_FLAGSEDITABLE', 2); /**#@-*/ -/// QTYPES INITIATION ////////////////// -// These variables get initialised via calls to question_register_questiontype -// as the question type classes are included. -global $QTYPES, $QTYPE_EXCLUDE_FROM_RANDOM; +/// GLOBAL VARAIBLES ////////////////// +global $QTYPES; /** - * Array holding question type objects + * Array holding question type objects. Initialised via calls to + * question_register_questiontype as the question type classes are included. */ $QTYPES = array(); -/** - * String in the format "'type1','type2'" that can be used in SQL clauses like - * "WHERE q.type NOT IN ($QTYPE_EXCLUDE_FROM_RANDOM)". - */ -$QTYPE_EXCLUDE_FROM_RANDOM = ''; /** * Add a new question type to the various global arrays above. @@ -139,16 +133,10 @@ $QTYPE_EXCLUDE_FROM_RANDOM = ''; * @param object $qtype An instance of the new question type class. */ function question_register_questiontype($qtype) { - global $QTYPES, $QTYPE_EXCLUDE_FROM_RANDOM; + global $QTYPES; $name = $qtype->name(); $QTYPES[$name] = $qtype; - if (!$qtype->is_usable_by_random()) { - if ($QTYPE_EXCLUDE_FROM_RANDOM) { - $QTYPE_EXCLUDE_FROM_RANDOM .= ','; - } - $QTYPE_EXCLUDE_FROM_RANDOM .= "'$name'"; - } } require_once("$CFG->dirroot/question/type/questiontype.php"); diff --git a/mod/quiz/report/grading/report.php b/mod/quiz/report/grading/report.php index 688337582c..f18673dec1 100644 --- a/mod/quiz/report/grading/report.php +++ b/mod/quiz/report/grading/report.php @@ -68,8 +68,9 @@ class quiz_grading_report extends quiz_default_report { } $gradeableqs = quiz_report_load_questions($quiz); - foreach ($gradeableqs as $qid => $questionformenu){ - if (!$QTYPES[$questionformenu->qtype]->is_manual_graded()){ + $questionsinuse = implode(',', array_keys($gradeableqs)); + foreach ($gradeableqs as $qid => $question){ + if (!$QTYPES[$question->qtype]->is_question_manual_graded($question, $questionsinuse)){ unset($gradeableqs[$qid]); } } diff --git a/question/type/essay/questiontype.php b/question/type/essay/questiontype.php index 9ad13e663b..5fe289e710 100644 --- a/question/type/essay/questiontype.php +++ b/question/type/essay/questiontype.php @@ -19,10 +19,6 @@ class question_essay_qtype extends default_questiontype { return true; } - function is_usable_by_random() { - return false; - } - function save_question_options($question) { global $DB; $result = true; diff --git a/question/type/questiontype.php b/question/type/questiontype.php index 267ddcb4ac..6015120879 100644 --- a/question/type/questiontype.php +++ b/question/type/questiontype.php @@ -85,12 +85,21 @@ class default_questiontype { } /** - * @return boolean true if this question can only be graded manually. + * @return boolean true if this question type may require manual grading. */ function is_manual_graded() { return false; } + /** + * @param object $question a question of this type. + * @param string $otherquestionsinuse comma-separate list of other question ids in this attempt. + * @return boolean true if a particular instance of this question requires manual grading. + */ + function is_question_manual_graded($question, $otherquestionsinuse) { + return $this->is_manual_graded(); + } + /** * @return boolean true if a table analyzing responses should be shown in * the quiz statistics report. Usually if a question is manually graded diff --git a/question/type/random/questiontype.php b/question/type/random/questiontype.php index 19d862e786..31e5f8663e 100644 --- a/question/type/random/questiontype.php +++ b/question/type/random/questiontype.php @@ -11,11 +11,13 @@ * @subpackage questiontypes */ class random_qtype extends default_questiontype { + protected $excludedqtypes = null; + protected $manualqtypes = null; // Caches questions available as randoms sorted by category // This is a 2-d array. The first key is question category, and the // second is whether to include subcategories. - var $catrandoms = array(); + private $catrandoms = array(); function name() { return 'random'; @@ -26,10 +28,65 @@ class random_qtype extends default_questiontype { return false; } + function show_analysis_of_responses() { + return true; + } + + function is_manual_graded() { + return true; + } + + function is_question_manual_graded($question, $otherquestionsinuse) { + global $DB; + // We take our best shot at working whether a particular question is manually + // graded follows: We look to see if any of the questions that this random + // question might select if of a manually graded type. If a category contains + // a mixture of manual and non-manual questions, and if all the attempts so + // far selected non-manual ones, this will give the wrong answer, but we + // don't care. Even so, this is an expensive calculation! + $this->init_qtype_lists(); + if (!$this->manualqtypes) { + return false; + } + if ($question->questiontext) { + $categorylist = question_categorylist($question->category); + } else { + $categorylist = $question->category; + } + return $DB->record_exists_select('question', + "category IN ($categorylist) + AND parent = 0 + AND hidden = 0 + AND id NOT IN ($otherquestionsinuse) + AND qtype IN ($this->manualqtypes)"); + } + function is_usable_by_random() { return false; } + /** + * This method needs to be called before the ->excludedqtypes and + * ->manualqtypes fields can be used. + */ + function init_qtype_lists() { + global $QTYPES; + if (is_null($this->excludedqtypes)) { + $excludedqtypes = array(); + $manualqtypes = array(); + foreach ($QTYPES as $qtype) { + $quotedname = "'" . $qtype->name() . "'"; + if (!$qtype->is_usable_by_random()) { + $excludedqtypes[] = $quotedname; + } else if ($qtype->is_manual_graded()) { + $manualqtypes[] = $quotedname; + } + } + $this->excludedqtypes = implode(',', $excludedqtypes); + $this->manualqtypes = implode(',', $manualqtypes); + } + } + function display_question_editing_page(&$mform, $question, $wizardnow){ list($heading, $langmodule) = $this->get_heading(empty($question->id)); print_heading_with_help($heading, $this->name(), $langmodule); @@ -87,7 +144,8 @@ class random_qtype extends default_questiontype { * @return array of question records. */ function get_usable_questions_from_category($categoryid, $subcategories, $questionsinuse) { - global $QTYPE_EXCLUDE_FROM_RANDOM, $DB; + global $DB; + $this->init_qtype_lists(); if ($subcategories) { $categorylist = question_categorylist($categoryid); } else { @@ -95,10 +153,10 @@ class random_qtype extends default_questiontype { } if (!$catrandoms = $DB->get_records_select('question', "category IN ($categorylist) - AND parent = '0' - AND hidden = '0' + AND parent = 0 + AND hidden = 0 AND id NOT IN ($questionsinuse) - AND qtype NOT IN ($QTYPE_EXCLUDE_FROM_RANDOM)", null, '', 'id')) { + AND qtype NOT IN ($this->excludedqtypes)", null, '', 'id')) { $catrandoms = array(); } return $catrandoms;