From a21567892f1d0f73222af5b1754c9aa983288f9e Mon Sep 17 00:00:00 2001 From: tjhunt Date: Tue, 15 Aug 2006 21:25:38 +0000 Subject: [PATCH] Refactor how question types register themselves with the question bank. This change makes it easier for 3rd party question types to control their destiny, but is also backwards compatible, in that old 3rd party plugins will still work. See http://moodle.org/mod/forum/discuss.php?d=51796 for more details. --- lib/questionlib.php | 58 ++++++++++++++++---- question/type/calculated/questiontype.php | 6 +- question/type/description/questiontype.php | 10 ++-- question/type/essay/questiontype.php | 15 +++-- question/type/match/questiontype.php | 5 +- question/type/missingtype/questiontype.php | 10 +++- question/type/multianswer/questiontype.php | 4 +- question/type/multichoice/questiontype.php | 5 +- question/type/numerical/questiontype.php | 5 +- question/type/questiontype.php | 44 +++++++++++++-- question/type/random/questiontype.php | 16 ++++-- question/type/randomsamatch/questiontype.php | 9 +-- question/type/rqp/questiontype.php | 12 ++-- question/type/shortanswer/questiontype.php | 5 +- question/type/truefalse/questiontype.php | 5 +- 15 files changed, 138 insertions(+), 71 deletions(-) diff --git a/lib/questionlib.php b/lib/questionlib.php index f772f04432..f153365d1d 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -37,7 +37,7 @@ define('QUESTION_EVENTMANUALGRADE', '9'); // Grade was entered by teacher /**#@-*/ /**#@+ - * The core question types - I don't think these constants are used any more. If so, they can be removed. + * The core question types. */ define("SHORTANSWER", "shortanswer"); define("TRUEFALSE", "truefalse"); @@ -78,13 +78,13 @@ define('QUESTION_ADAPTIVE', 1); /**#@-*/ /// QTYPES INITIATION ////////////////// - +// These variables get initialised via calls to question_register_questiontype +// as the question type classes are included. +global $QTYPES, $QTYPE_MENU, $QTYPE_MANUAL, $QTYPE_EXCLUDE_FROM_RANDOM; /** * Array holding question type objects */ -global $QTYPES; -$QTYPES = array(); // This array will be populated when the questiontype.php files are loaded below - +$QTYPES = array(); /** * Array of question types names translated to the user's language * @@ -92,15 +92,51 @@ $QTYPES = array(); // This array will be populated when the questiontype.php fil * be able to create directly. Some internal question types like random questions are excluded. * The complete list of question types can be found in {@link $QTYPES}. */ -$QTYPE_MENU = array(); // This array will be populated when the questiontype.php files are loaded +$QTYPE_MENU = array(); +/** + * String in the format "'type1','type2'" that can be used in SQL clauses like + * "WHERE q.type IN ($QTYPE_MANUAL)". + */ +$QTYPE_MANUAL = ''; +/** + * 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. + * + * @param object $qtype An instance of the new question type class. + */ +function question_register_questiontype($qtype) { + global $QTYPES, $QTYPE_MENU, $QTYPE_MANUAL, $QTYPE_EXCLUDE_FROM_RANDOM; + + $name = $qtype->name(); + $QTYPES[$name] = $qtype; + $menuname = $qtype->menu_name(); + if ($menuname) { + $QTYPE_MENU[$name] = $menuname; + } + if ($qtype->is_manual_graded()) { + if ($QTYPE_MANUAL) { + $QTYPE_MANUAL .= ','; + } + $QTYPE_MANUAL .= "'$name'"; + } + 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"); -/* -* Load the questiontype.php file for each question type -* These files in turn instantiate the corresponding question type class -* and add them to the $QTYPES array -*/ +// Load the questiontype.php file for each question type +// These files in turn call question_register_questiontype() +// with a new instance of each qtype class. $qtypenames= get_list_of_plugins('question/type'); foreach($qtypenames as $qtypename) { // Instanciates all plug-in question types diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php index 539962d9e7..3131630dec 100644 --- a/question/type/calculated/questiontype.php +++ b/question/type/calculated/questiontype.php @@ -1,7 +1,7 @@ diff --git a/question/type/essay/questiontype.php b/question/type/essay/questiontype.php index a15be1e632..bd4d541eb2 100644 --- a/question/type/essay/questiontype.php +++ b/question/type/essay/questiontype.php @@ -10,6 +10,14 @@ class question_essay_qtype extends default_questiontype { function name() { return 'essay'; } + + function is_manual_graded() { + return true; + } + + function is_usable_by_random() { + return false; + } function save_question_options($question) { if ($answer = get_record("question_answers", "question", $question->id)) { @@ -104,10 +112,5 @@ class question_essay_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['essay'] = new question_essay_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['essay'] = get_string("essay", "quiz"); -// Add essay to the list of manually graded questions -$QTYPE_MANUAL = isset($QTYPE_MANUAL) ? $QTYPE_MANUAL.",'essay'" : "'essay'"; - +question_register_questiontype(new question_essay_qtype()); ?> diff --git a/question/type/match/questiontype.php b/question/type/match/questiontype.php index 17a1707a68..93248b2a02 100644 --- a/question/type/match/questiontype.php +++ b/question/type/match/questiontype.php @@ -595,8 +595,5 @@ class question_match_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['match']= new question_match_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['match'] = get_string("match", "quiz"); - +question_register_questiontype(new question_match_qtype()); ?> diff --git a/question/type/missingtype/questiontype.php b/question/type/missingtype/questiontype.php index 6493f3bd9b..94a417d364 100644 --- a/question/type/missingtype/questiontype.php +++ b/question/type/missingtype/questiontype.php @@ -18,6 +18,14 @@ class question_missingtype_qtype extends default_questiontype { function name() { return 'missingtype'; } + + function menu_name() { + return false; + } + + function is_usable_by_random() { + return false; + } function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { global $CFG; @@ -56,6 +64,6 @@ class question_missingtype_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['missingtype']= new question_missingtype_qtype(); +question_register_questiontype(new question_missingtype_qtype()); ?> diff --git a/question/type/multianswer/questiontype.php b/question/type/multianswer/questiontype.php index ece94a7727..0dd0396333 100644 --- a/question/type/multianswer/questiontype.php +++ b/question/type/multianswer/questiontype.php @@ -584,9 +584,7 @@ class embedded_cloze_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['multianswer']= new embedded_cloze_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['multianswer'] = get_string("multianswer", "quiz"); +question_register_questiontype(new embedded_cloze_qtype()); ///////////////////////////////////////////////////////////// //// ADDITIONAL FUNCTIONS diff --git a/question/type/multichoice/questiontype.php b/question/type/multichoice/questiontype.php index 86612dfb21..44ccadff9e 100644 --- a/question/type/multichoice/questiontype.php +++ b/question/type/multichoice/questiontype.php @@ -513,8 +513,5 @@ class question_multichoice_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['multichoice']= new question_multichoice_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['multichoice'] = get_string("multichoice", "quiz"); - +question_register_questiontype(new question_multichoice_qtype()); ?> diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index 70fb65d14a..7d53649a1f 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -500,8 +500,5 @@ class question_numerical_qtype extends question_shortanswer_qtype { } // INITIATION - Without this line the question type is not in use. -$QTYPES['numerical']= new question_numerical_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['numerical'] = get_string("numerical", "quiz"); - +question_register_questiontype(new question_numerical_qtype()); ?> diff --git a/question/type/questiontype.php b/question/type/questiontype.php index ab2478fd1b..2bae2e6de9 100644 --- a/question/type/questiontype.php +++ b/question/type/questiontype.php @@ -16,16 +16,48 @@ class default_questiontype { /** - * Name of the question type - * - * The name returned should coincide with the name of the directory - * in which this questiontype is located - * @ return string - */ + * Name of the question type + * + * The name returned should coincide with the name of the directory + * in which this questiontype is located + * + * @ return string the name of this question type. + */ function name() { return 'default'; } + /** + * The name this question should appear as in the create new question + * dropdown. + * + * @return mixed the desired string, or false to hide this question type in the menu. + */ + function menu_name() { + $name = $this->name(); + $menu_name = get_string($name, 'qtype_' . $name); + if ($menu_name[0] == '[') { + // Legacy behavior, if the string was not in the proper qtype_name + // language file, look it up in the quiz one. + $menu_name = get_string($this->name(), 'quiz'); + } + return $menu_name; + } + + /** + * @return boolean true if this question can only be graded manually. + */ + function is_manual_graded() { + return false; + } + + /** + * @return boolean true if this question type can be used by the random question type. + */ + function is_usable_by_random() { + return true; + } + /** * Saves or updates a question after editing by a teacher * diff --git a/question/type/random/questiontype.php b/question/type/random/questiontype.php index 2f35ca1415..e473696043 100644 --- a/question/type/random/questiontype.php +++ b/question/type/random/questiontype.php @@ -7,8 +7,6 @@ /// QUESTION TYPE CLASS ////////////////// class random_qtype extends default_questiontype { - var $excludedtypes = array("'random'", "'randomsamatch'", "'essay'", "'description'"); - // Carries questions available as randoms sorted by category // This array is used when needed only var $catrandoms = array(); @@ -17,6 +15,14 @@ class random_qtype extends default_questiontype { return 'random'; } + function menu_name() { + return false; + } + + function is_usable_by_random() { + return false; + } + function get_question_options(&$question) { // Don't do anything here, because the random question has no options. // Everything is handled by the create- or restore_session_and_responses @@ -32,6 +38,7 @@ class random_qtype extends default_questiontype { } function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { + global $QTYPE_EXCLUDE_FROM_RANDOM; // Choose a random question from the category: // We need to make sure that no question is used more than once in the // quiz. Therfore the following need to be excluded: @@ -46,7 +53,6 @@ class random_qtype extends default_questiontype { // Need to fetch random questions from category $question->category" // (Note: $this refers to the questiontype, not the question.) global $CFG; - $excludedtypes = implode(',', $this->excludedtypes); if ($question->questiontext == "1") { // recurse into subcategories $categorylist = question_categorylist($question->category); @@ -58,7 +64,7 @@ class random_qtype extends default_questiontype { WHERE category IN ($categorylist) AND parent = '0' AND id NOT IN ($cmoptions->questionsinuse) - AND qtype NOT IN ($excludedtypes)")) { + AND qtype NOT IN ($QTYPE_EXCLUDE_FROM_RANDOM)")) { $this->catrandoms[$question->category][$question->questiontext] = draw_rand_array($catrandoms, count($catrandoms)); // from bug 1889 } else { @@ -242,6 +248,6 @@ class random_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES[RANDOM]= new random_qtype(); +question_register_questiontype(new random_qtype()); ?> diff --git a/question/type/randomsamatch/questiontype.php b/question/type/randomsamatch/questiontype.php index 21f16fd94b..e2a968dfbe 100644 --- a/question/type/randomsamatch/questiontype.php +++ b/question/type/randomsamatch/questiontype.php @@ -15,6 +15,10 @@ class question_randomsamatch_qtype extends question_match_qtype { return 'randomsamatch'; } + function is_usable_by_random() { + return false; + } + function get_question_options(&$question) { if (!$question->options = get_record('question_randomsamatch', 'question', $question->id)) { notify('Error: Missing question options for random short answer question '.$question->id.'!'); @@ -351,8 +355,5 @@ class question_randomsamatch_qtype extends question_match_qtype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['randomsamatch']= new question_randomsamatch_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['randomsamatch'] = get_string("randomsamatch", "quiz"); - +question_register_questiontype(new question_randomsamatch_qtype()); ?> diff --git a/question/type/rqp/questiontype.php b/question/type/rqp/questiontype.php index 68d45d5564..605a151466 100644 --- a/question/type/rqp/questiontype.php +++ b/question/type/rqp/questiontype.php @@ -18,15 +18,15 @@ require_once($CFG->dirroot . '/question/type/rqp/remote.php'); */ class question_rqp_qtype extends default_questiontype { - /** - * Name of the rqp question type - * - * @ return string 'rqp' - */ function name() { return 'rqp'; } + function menu_name() { + // Does not currently work, so don't include in the menu. + return false; + } + /** * Save the type-specific options * @@ -547,6 +547,6 @@ class question_rqp_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES[RQP]= new question_rqp_qtype(); +question_register_questiontype(new question_rqp_qtype()); ?> diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php index 061a6c26c6..b34af78e0d 100644 --- a/question/type/shortanswer/questiontype.php +++ b/question/type/shortanswer/questiontype.php @@ -319,8 +319,5 @@ class question_shortanswer_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['shortanswer']= new question_shortanswer_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['shortanswer'] = get_string("shortanswer", "quiz"); - +question_register_questiontype(new question_shortanswer_qtype()); ?> diff --git a/question/type/truefalse/questiontype.php b/question/type/truefalse/questiontype.php index 96d20c1515..97782ce903 100644 --- a/question/type/truefalse/questiontype.php +++ b/question/type/truefalse/questiontype.php @@ -321,8 +321,5 @@ class question_truefalse_qtype extends default_questiontype { ////////////////////////////////////////////////////////////////////////// //// INITIATION - Without this line the question type is not in use... /// ////////////////////////////////////////////////////////////////////////// -$QTYPES['truefalse']= new question_truefalse_qtype(); -// The following adds the questiontype to the menu of types shown to teachers -$QTYPE_MENU['truefalse'] = get_string("truefalse", "quiz"); - +question_register_questiontype(new question_truefalse_qtype()); ?> -- 2.39.5