Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/question/engine/bank.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 
00031 defined('MOODLE_INTERNAL') || die();
00032 
00033 require_once(dirname(__FILE__) . '/../type/questiontypebase.php');
00034 
00035 
00044 abstract class question_bank {
00045     // TODO: This limit can be deleted if someday we move all TEXTS to BIG ones. MDL-19603
00046     const MAX_SUMMARY_LENGTH = 32000;
00047 
00049     private static $questiontypes = array();
00050 
00052     private static $loadedqdefs = array();
00053 
00054     protected static $questionfinder = null;
00055 
00057     private static $testmode = false;
00058     private static $testdata = array();
00059 
00060     private static $questionconfig = null;
00061 
00069     private static $fractionoptions = null;
00071     private static $fractionoptionsfull = null;
00072 
00077     public static function is_qtype_installed($qtypename) {
00078         $plugindir = get_plugin_directory('qtype', $qtypename);
00079         return $plugindir && is_readable($plugindir . '/questiontype.php');
00080     }
00081 
00089     public static function get_qtype($qtypename, $mustexist = true) {
00090         global $CFG;
00091         if (isset(self::$questiontypes[$qtypename])) {
00092             return self::$questiontypes[$qtypename];
00093         }
00094         $file = get_plugin_directory('qtype', $qtypename) . '/questiontype.php';
00095         if (!is_readable($file)) {
00096             if ($mustexist || $qtypename == 'missingtype') {
00097                 throw new coding_exception('Unknown question type ' . $qtypename);
00098             } else {
00099                 return self::get_qtype('missingtype');
00100             }
00101         }
00102         include_once($file);
00103         $class = 'qtype_' . $qtypename;
00104         if (!class_exists($class)) {
00105             throw new coding_exception("Class $class must be defined in $file");
00106         }
00107         self::$questiontypes[$qtypename] = new $class();
00108         return self::$questiontypes[$qtypename];
00109     }
00110 
00115     public static function get_config() {
00116         if (is_null(self::$questionconfig)) {
00117             self::$questionconfig = get_config('question');
00118         }
00119         return self::$questionconfig;
00120     }
00121 
00126     public static function qtype_enabled($qtypename) {
00127         $config = self::get_config();
00128         $enabledvar = $qtypename . '_disabled';
00129         return self::qtype_exists($qtypename) && empty($config->$enabledvar) &&
00130                 self::get_qtype($qtypename)->menu_name() != '';
00131     }
00132 
00137     public static function qtype_exists($qtypename) {
00138         return array_key_exists($qtypename, get_plugin_list('qtype'));
00139     }
00140 
00145     public static function get_qtype_name($qtypename) {
00146         return self::get_qtype($qtypename)->local_name();
00147     }
00148 
00152     public static function get_all_qtypes() {
00153         $qtypes = array();
00154         foreach (get_plugin_list('qtype') as $plugin => $notused) {
00155             try {
00156                 $qtypes[$plugin] = self::get_qtype($plugin);
00157             } catch (coding_exception $e) {
00158                 // Catching coding_exceptions here means that incompatible
00159                 // question types do not cause the rest of Moodle to break.
00160             }
00161         }
00162         return $qtypes;
00163     }
00164 
00171     public static function sort_qtype_array($qtypes, $config = null) {
00172         if (is_null($config)) {
00173             $config = self::get_config();
00174         }
00175 
00176         $sortorder = array();
00177         $otherqtypes = array();
00178         foreach ($qtypes as $name => $localname) {
00179             $sortvar = $name . '_sortorder';
00180             if (isset($config->$sortvar)) {
00181                 $sortorder[$config->$sortvar] = $name;
00182             } else {
00183                 $otherqtypes[$name] = $localname;
00184             }
00185         }
00186 
00187         ksort($sortorder);
00188         collatorlib::asort($otherqtypes);
00189 
00190         $sortedqtypes = array();
00191         foreach ($sortorder as $name) {
00192             $sortedqtypes[$name] = $qtypes[$name];
00193         }
00194         foreach ($otherqtypes as $name => $notused) {
00195             $sortedqtypes[$name] = $qtypes[$name];
00196         }
00197         return $sortedqtypes;
00198     }
00199 
00204     public static function get_creatable_qtypes() {
00205         $config = self::get_config();
00206         $allqtypes = self::get_all_qtypes();
00207 
00208         $qtypenames = array();
00209         foreach ($allqtypes as $name => $qtype) {
00210             if (self::qtype_enabled($name)) {
00211                 $qtypenames[$name] = $qtype->local_name();
00212             }
00213         }
00214 
00215         $qtypenames = self::sort_qtype_array($qtypenames);
00216 
00217         $creatableqtypes = array();
00218         foreach ($qtypenames as $name => $notused) {
00219             $creatableqtypes[$name] = $allqtypes[$name];
00220         }
00221         return $creatableqtypes;
00222     }
00223 
00230     public static function load_question_definition_classes($qtypename) {
00231         global $CFG;
00232         if (isset(self::$loadedqdefs[$qtypename])) {
00233             return;
00234         }
00235         $file = $CFG->dirroot . '/question/type/' . $qtypename . '/question.php';
00236         if (!is_readable($file)) {
00237             throw new coding_exception('Unknown question type (no definition) ' . $qtypename);
00238         }
00239         include_once($file);
00240         self::$loadedqdefs[$qtypename] = 1;
00241     }
00242 
00251     public static function load_question($questionid, $allowshuffle = true) {
00252         global $DB;
00253 
00254         if (self::$testmode) {
00255             // Evil, test code in production, but now way round it.
00256             return self::return_test_question_data($questionid);
00257         }
00258 
00259         $questiondata = $DB->get_record_sql('
00260                 SELECT q.*, qc.contextid
00261                 FROM {question} q
00262                 JOIN {question_categories} qc ON q.category = qc.id
00263                 WHERE q.id = :id', array('id' => $questionid), MUST_EXIST);
00264         get_question_options($questiondata);
00265         if (!$allowshuffle) {
00266             $questiondata->options->shuffleanswers = false;
00267         }
00268         return self::make_question($questiondata);
00269     }
00270 
00277     public static function make_question($questiondata) {
00278         return self::get_qtype($questiondata->qtype, false)->make_question($questiondata, false);
00279     }
00280 
00284     public static function get_finder() {
00285         if (is_null(self::$questionfinder)) {
00286             self::$questionfinder = new question_finder();
00287         }
00288         return self::$questionfinder;
00289     }
00290 
00294     public static function start_unit_test() {
00295         self::$testmode = true;
00296     }
00297 
00301     public static function end_unit_test() {
00302         self::$testmode = false;
00303         self::$testdata = array();
00304     }
00305 
00306     private static function return_test_question_data($questionid) {
00307         if (!isset(self::$testdata[$questionid])) {
00308             throw new coding_exception('question_bank::return_test_data(' . $questionid .
00309                     ') called, but no matching question has been loaded by load_test_data.');
00310         }
00311         return self::$testdata[$questionid];
00312     }
00313 
00319     public static function load_test_question_data(question_definition $question) {
00320         if (!self::$testmode) {
00321             throw new coding_exception('question_bank::load_test_data called when ' .
00322                     'not in test mode.');
00323         }
00324         self::$testdata[$question->id] = $question;
00325     }
00326 
00327     protected function ensure_fraction_options_initialised() {
00328         if (!is_null(self::$fractionoptions)) {
00329             return;
00330         }
00331 
00332         // define basic array of grades. This list comprises all fractions of the form:
00333         // a. p/q for q <= 6, 0 <= p <= q
00334         // b. p/10 for 0 <= p <= 10
00335         // c. 1/q for 1 <= q <= 10
00336         // d. 1/20
00337         $rawfractions = array(
00338             0.9000000,
00339             0.8333333,
00340             0.8000000,
00341             0.7500000,
00342             0.7000000,
00343             0.6666667,
00344             0.6000000,
00345             0.5000000,
00346             0.4000000,
00347             0.3333333,
00348             0.3000000,
00349             0.2500000,
00350             0.2000000,
00351             0.1666667,
00352             0.1428571,
00353             0.1250000,
00354             0.1111111,
00355             0.1000000,
00356             0.0500000,
00357         );
00358 
00359         // Put the None option at the top.
00360         self::$fractionoptions = array(
00361             '0.0' => get_string('none'),
00362             '1.0' => '100%',
00363         );
00364         self::$fractionoptionsfull = array(
00365             '0.0' => get_string('none'),
00366             '1.0' => '100%',
00367         );
00368 
00369         // The the positive grades in descending order.
00370         foreach ($rawfractions as $fraction) {
00371             $percentage = (100 * $fraction) . '%';
00372             self::$fractionoptions["$fraction"] = $percentage;
00373             self::$fractionoptionsfull["$fraction"] = $percentage;
00374         }
00375 
00376         // The the negative grades in descending order.
00377         foreach (array_reverse($rawfractions) as $fraction) {
00378             self::$fractionoptionsfull['' . (-$fraction)] = (-100 * $fraction) . '%';
00379         }
00380 
00381         self::$fractionoptionsfull['-1.0'] = '-100%';
00382     }
00383 
00391     public static function fraction_options() {
00392         self::ensure_fraction_options_initialised();
00393         return self::$fractionoptions;
00394     }
00395 
00397     public static function fraction_options_full() {
00398         self::ensure_fraction_options_initialised();
00399         return self::$fractionoptionsfull;
00400     }
00401 }
00402 
00403 
00410 class question_finder {
00420     public function get_questions_from_categories($categoryids, $extraconditions,
00421             $extraparams = array()) {
00422         global $DB;
00423 
00424         list($qcsql, $qcparams) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'qc');
00425 
00426         if ($extraconditions) {
00427             $extraconditions = ' AND (' . $extraconditions . ')';
00428         }
00429 
00430         return $DB->get_records_select_menu('question',
00431                 "category $qcsql
00432                  AND parent = 0
00433                  AND hidden = 0
00434                  $extraconditions", $qcparams + $extraparams, '', 'id,id AS id2');
00435     }
00436 }
 All Data Structures Namespaces Files Functions Variables Enumerations