From: tjhunt Date: Wed, 21 Jan 2009 08:49:15 +0000 (+0000) Subject: question bank: MDL-17302 refactor question bank display code into a class. X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=b221dc6f23e7e085b1a2daf16e4febfcf78843cc;p=moodle.git question bank: MDL-17302 refactor question bank display code into a class. Step 3. Start working ot the code to initialise things from a list of columns, and build the corresponding SQL query. --- diff --git a/lang/en_utf8/error.php b/lang/en_utf8/error.php index 2224c09da6..f8a7668471 100644 --- a/lang/en_utf8/error.php +++ b/lang/en_utf8/error.php @@ -441,6 +441,7 @@ $string['unknownrole'] = 'Unknown role \"$a\"'; $string['unknownuseraction'] = 'Sorry, I do not understand this user action'; $string['unknownuserselector'] = 'Unknown user selector'; $string['unknownmodulename'] = 'Unknown module name for form'; +$string['unknownsortcolumn'] = 'Unknown sort column $a'; $string['unknoworder'] = 'Unknown ordering'; $string['unknowparamtype'] = 'Unknown parameter type: $a'; $string['unknowquestiontype'] = 'Unsupported question type $a'; diff --git a/question/editlib.php b/question/editlib.php index dace592036..371d64fe2f 100644 --- a/question/editlib.php +++ b/question/editlib.php @@ -238,7 +238,8 @@ abstract class question_bank_column_base { /** * @param object $question the row from the $question table, augmented with extra information. - * @return string internal name for this column. Used as a CSS class name, and to store information about the current sort. + * @return string internal name for this column. Used as a CSS class name, + * and to store information about the current sort. Must match PARAM_ALPHA. */ abstract protected function get_name(); @@ -262,6 +263,9 @@ abstract class question_bank_column_base { * If to columns try to use the same alias with different joins, you get an error. * The only table included by default is the question table, which is aliased to 'q'. * + * It is importnat that your join simply adds additional data (or NULLs) to the + * existing rows of the query. It must not cause additional rows. + * * @return array 'table_alias' => 'JOIN clause' */ public function get_extra_joins() { @@ -625,6 +629,12 @@ class question_bank_view { protected $quizorcourseid; protected $contexts; protected $cm; + protected $knowncolumntypes; + protected $visiblecolumns; + protected $requiredcolumns; + protected $sort; + protected $countsql; + protected $loadsql; public function __construct($contexts, $pageurl, $cm = null) { global $CFG, $COURSE; @@ -647,6 +657,137 @@ class question_bank_view { } else { $this->editquestionurl->param('courseid', $COURSE->id); } + + $this->init_column_types(); + $this->init_columns(array('checkbox', 'qtype', 'questionname', 'creatorname', + 'modifiername', 'editaction', 'previewaction', 'moveaction', 'deleteaction')); + $this->init_sort(); + } + + protected function init_columns() { + $types = array( + new question_bank_checkbox_column($this), + new question_bank_question_type_column($this), + new question_bank_question_name_column($this), + new question_bank_creator_name_column($this), + new question_bank_modifier_name_column($this), + new question_bank_edit_action_column($this), + new question_bank_preview_action_column($this), + new question_bank_move_action_column($this), + new question_bank_delete_action_column($this), + ); + $this->knowncolumntypes = array(); + foreach ($columns as $col) { + $this->knowncolumntypes[$col->get_name()] = $col; + } + } + + protected function init_columns($wanted) { + $this->visiblecolumns = array(); + foreach ($wanted as $colname) { + if (!isset($this->knowncolumntypes[$colname])) { + throw new coding_exception('Unknown column type ' . $colname . ' requested in init columns.'); + } + $this->visiblecolumns[$colname] = $this->knowncolumntypes[$colname]; + } + $this->requiredcolumns = $this->visiblecolumns; + } + + protected function init_sort() { + $this->init_sort_from_params(); + if (empty($this->sort)) { + $this->sort = $this->default_sort(); + } + } + + /** + * Deal with a sort name of the forum columnname, or colname_subsort by + * breaking it up, validating the bits that are presend, and returning them. + * If there is no subsort, then $subsort is returned as ''. + * @return array array($colname, $subsort). + */ + protected function parse_subsort($sort) { + /// Do the parsing. + if (strpos($sort, '_') !== false) { + list($colname, $subsort) = explode('_', $sort, 2); + } else { + $colname = $sort; + $subsort = ''; + } + /// Validate the column name. + if (!isset($this->knowncolumntypes[$colname]) || !$this->knowncolumntypes[$colname]->is_sortable()) { + $this->baseurl->remove_params('qbs1', 'qbs2', 'qbs3'); + throw new moodle_exception('unknownsortcolumn', '', $link = $this->baseurl->out(), $colname); + } + /// Validate the subsort, if present. + if ($subsort) { + $subsorts = $this->knowncolumntypes[$colname]->is_sortable(); + if (!is_array($subsorts) || !isset($subsorts[$subsort])) { + throw new moodle_exception('unknownsortcolumn', '', $link = $this->baseurl->out(), $sort); + } + } + return array($colname, $subsort); + } + + protected function init_sort_from_params() { + $this->sort = array(); + for ($i = 1; $i < 3; $i++) { + if (!$sort = optional_param('qbs1', '', PARAM_ALPHAEXT)) { + break; + } + // Work out the appropriate order. + $order = 1; + if ($sort[0] == '-') { + $order = -1; + $sort = substr($sort1, 1); + if (!$sort) { + break; + } + } + // Deal with subsorts. + list($colname, $subsort) = $this->parse_subsort($sort); + $this->requiredcolumns[$colname] = $this->knowncolumntypes[$colname]; + $sort[$sort] = $order; + } + } + + protected function default_sort() { + return array('qtype' => 1, 'questionname' => 1); + } + + protected function build_query_sql() { + /// Get the required tables. + $joins = array(); + foreach ($this->requiredcolumns as $column) { + $extrajoins = $column->get_extra_joins(); + foreach ($extrajoins as $prefix => $join) { + if (isset($joins[$prefix]) && $joins[$prefix] != $join) { + throw new coding_exception('Join ' . $join . ' conflicts with previous join ' . $joins[$prefix]); + } + $joins[$prefix] = $join; + } + } + + /// Get the required fields. + $fields = array(); + foreach ($this->visiblecolumns as $column) { + $fields += $column->get_required_fields(); + } + $fields = array_unique($fields); + + /// Build the order by clause. + $sorts = array(); + foreach ($this->sort as $sort => $order) { + list($colname, $subsort) = $this->parse_subsort($sort); + $sorts[] = $this->knowncolumntypes[$colname]->sort_expression($order < 0, $subsort); + } + + /// Build the SQL. + $sql = ' FROM {question} q ' . implode(' ', $joins); + // TODO where clause. + $sql .= ' ORDER BY ' . implode(', ', $sorts); + $this->countsql = 'SELECT count(1)' . $sql; + $this->loadsql = 'SELECT ' . implode(', ', $fields) . $sql; } public function base_url($questionid) {