]> git.mjollnir.org Git - moodle.git/commitdiff
question bank: MDL-17871 refactor the code that displays particular information about...
authortjhunt <tjhunt>
Tue, 20 Jan 2009 10:11:23 +0000 (10:11 +0000)
committertjhunt <tjhunt>
Tue, 20 Jan 2009 10:11:23 +0000 (10:11 +0000)
Work in progress. Most required classes are writted, but nothing uses them yet, and I have not dealt with column headers yet.

question/editlib.php

index c21b1eabbb33253f260161c54f93adc3a498cebc..7c02d41217d28c6f7bfe14bcadbe8727d857b263 100644 (file)
@@ -127,6 +127,397 @@ function question_can_delete_cat($todelete) {
     }
 }
 
+abstract class question_bank_column_base {
+
+    /**
+     * Output the column header cell.
+     * @param integer $currentsort 0 for none. 1 for normal sort, -1 for reverse sort.
+     */
+    public function display_header($currentsort) {
+        // TODO.
+    }
+
+    /**
+     * Output this column.
+     * @param object $question the row from the $question table, augmented with extra information.
+     * @param string $rowclasses CSS class names that should be applied to this row of output.
+     */
+    public function display($question, $rowclasses) {
+        $this->display_start($question, $rowclasses);
+        $this->display_content($question, $rowclasses);
+        $this->display_end($question, $rowclasses);
+    }
+
+    protected function display_start($question, $rowclasses) {
+        echo '<td class="' . $this->get_css_classes($question, $rowclasses) . '">';
+    }
+
+    /**
+     * @param object $question the row from the $question table, augmented with extra information.
+     * @param string $rowclasses CSS class names that should be applied to this row of output.
+     * @return string CSS class names that should be applied to this column. Should normally be
+     *      a simple work relating the the column type like 'questionname'.
+     */
+    abstract protected function get_css_classes($question, $rowclasses);
+
+    /**
+     * Output the contents of this column.
+     * @param object $question the row from the $question table, augmented with extra information.
+     * @param string $rowclasses CSS class names that should be applied to this row of output.
+     */
+    abstract protected function display_content($question, $rowclasses);
+
+    protected function display_end($question, $rowclasses) {
+        echo '</td>';
+    }
+
+    /**
+     * Return an array 'table_alias' => 'JOIN clause' to bring in any data that
+     * this column required.
+     *
+     * The return values for all the columns will be checked. It is OK if two
+     * columns join in the same table with the same alias and identical JOIN clauses.
+     * 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'.
+     *
+     * @return array 'table_alias' => 'JOIN clause'
+     */
+    public function get_extra_joins() {
+        return array();
+    }
+
+    /**
+     * @return array fields required. use table alias 'q' for the question table, or one of the
+     * ones from get_extra_joins. Every field requested must specify a table prefix.
+     */
+    public function get_required_fields() {
+        return array();
+    }
+
+    /**
+     * Can this column be sorted on? You can return either:
+     *  + false for no (the default),
+     *  + true for yes, or
+     *  + an array of subnames to sort on. E.g. 'firstname', 'lastname'.
+     * If this method returns true, sort_expression must be implemented.
+     * @return mixed  
+     */
+    public function is_sortable() {
+        return false;
+    }
+
+    /**
+     * Helper method for building sort clauses.
+     * @param boolean $reverse whether the normal direction should be reversed.
+     * @param string $normaldir 'ASC' or 'DESC'
+     * @return string 'ASC' or 'DESC'
+     */
+    protected function sortorder($reverse, $normaldir = 'ASC') {
+        switch ($normaldir) {
+            case 'ASC':
+                if ($reverse) {
+                    return ' DESC';
+                } else {
+                    return ' ASC';
+                }
+            case 'DESC':
+                if ($reverse) {
+                    return ' ASC';
+                } else {
+                    return ' DESC';
+                }
+            default:
+                throw new coding_exception('$normaldir should be ASC or DESC.');
+        }
+    }
+
+    /**
+     * @param $reverse Whether to sort in the reverse of the default sort order.
+     * @param $subsort if is_sortable returns an array of subnames, then this will be
+     *      one of those. Otherwise will be empty.
+     * @return string some SQL to go in the order by clause.
+     */
+    public function sort_expression($reverse, $subsort) {
+        throw new coding_exception('A subclass of question_bank_column_base must implement sort_expression if is_sortable returns true.');
+    }
+}
+
+/**
+ * A column with a checkbox for each question with name q{questionid}.
+ */
+class question_bank_checkbox_column extends question_bank_column_base {
+    protected $strselect;
+
+    public function __construct() {
+        parent::__construct();
+        $this->strselect = get_string('select', 'quiz');
+    }
+
+    protected function get_css_classes($question, $rowclasses) {
+        return 'checkbox';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        echo '<input title="' . $this->strselect . '" type="checkbox" name="q' .
+                $question->id . '" id="checkq' . $question->id . '" value="1" />';
+    }
+
+    public function get_required_fields() {
+        return array('q.id');
+    }
+}
+
+/**
+ * A column type for the name of the question type.
+ */
+class question_bank_question_type_column extends question_bank_column_base {
+    protected function get_css_classes($question, $rowclasses) {
+        return 'qtype';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        echo print_question_icon($question);
+    }
+
+    public function get_required_fields() {
+        return array('q.qtype');
+    }
+
+    public function is_sortable() {
+        return true;
+    }
+
+    public function sort_expression($reverse, $subsort) {
+        return 'q.qtype' . $this->sortorder($reverse);
+    }
+}
+
+/**
+ * A column type for the name of the question name.
+ */
+class question_bank_question_name_column extends question_bank_column_base {
+    protected function get_css_classes($question, $rowclasses) {
+        return 'questionname';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        echo format_string($question->name);
+    }
+
+    public function get_required_fields() {
+        return array('q.name');
+    }
+
+    public function is_sortable() {
+        return true;
+    }
+
+    public function sort_expression($reverse, $subsort) {
+        return 'q.name' . $this->sortorder($reverse);
+    }
+}
+
+/**
+ * A column type for the name of the question creator.
+ */
+class question_bank_creator_name_column extends question_bank_column_base {
+    protected function get_css_classes($question, $rowclasses) {
+        return 'creatorname';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (!empty($question->creatorfirstname) && !empty($question->creatorlastname)) {
+            $u = new stdClass;
+            $u->firstname = $question->creatorfirstname;
+            $u->lastname = $question->creatorlastname;
+            echo fullname($u);
+        }
+    }
+
+    public function get_extra_joins() {
+        return array('uc' => 'LEFT JOIN {user} uc ON uc.id = q.createdby');
+    }
+
+    public function get_required_fields() {
+        return array('uc.firstname AS creatorfirstname', 'uc.lastname AS creatorlastname');
+    }
+
+    public function is_sortable() {
+        return array('firstname', 'lastname');
+    }
+
+    public function sort_expression($reverse, $subsort) {
+        if (in_array($subsort, $this->is_sortable())) {
+            return 'uc.' . $subsort . $this->sortorder($reverse);
+        } else {
+            throw new coding_exception('Unexpected $subsort type.');
+        }
+    }
+}
+
+/**
+ * A column type for the name of the question last modifier.
+ */
+class question_bank_modifier_name_column extends question_bank_column_base {
+    protected function get_css_classes($question, $rowclasses) {
+        return 'modifiername';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (!empty($question->modifierfirstname) && !empty($question->modifierlastname)) {
+            $u = new stdClass;
+            $u->firstname = $question->modifierfirstname;
+            $u->lastname = $question->modifierlastname;
+            echo fullname($u);
+        }
+    }
+
+    public function get_extra_joins() {
+        return array('um' => 'LEFT JOIN {user} um ON um.id = q.modifiedby');
+    }
+
+    public function get_required_fields() {
+        return array('um.firstname AS modifierfirstname', 'um.lastname AS modifierlastname');
+    }
+
+    public function is_sortable() {
+        return array('firstname', 'lastname');
+    }
+
+    public function sort_expression($reverse, $subsort) {
+        if (in_array($subsort, $this->is_sortable())) {
+            return 'um.' . $subsort . $this->sortorder($reverse);
+        } else {
+            throw new coding_exception('Unexpected $subsort type.');
+        }
+    }
+}
+
+/**
+ * A base class for actions that are an icon that lets you manipulate the question in some way.
+ */
+abstract class question_bank_action_column_base extends question_bank_column_base {
+    protected function print_icon($icon, $title, $url) {
+        global $CFG;
+        echo '<a title="' . $title . '" href="' . $url . '">
+                <img src="' . $CFG->pixpath . '/t/' . $icon . '" class="iconsmall" alt="' . $title . '" /></a>';
+    }
+
+    public function get_required_fields() {
+        return array('q.id');
+    }
+}
+
+class question_bank_edit_action_column extends question_bank_action_column_base {
+    protected $stredit;
+    protected $strview;
+    protected $questionurl;
+
+    public function __construct($questionurl) {
+        parent::__construct();
+        $this->questionurl = $questionurl;
+        $this->stredit = get_string('edit');
+        $this->strview = get_string('view');
+    }
+
+    protected function get_css_classes($question, $rowclasses) {
+        return 'editaction';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (question_has_capability_on($question, 'edit') ||
+                question_has_capability_on($question, 'move')) {
+            $this->print_icon('edit', $this->stredit, $this->questionurl->out(false, array('id' => $question->id)));
+        } else {
+            $this->print_icon('info', $this->strview, $this->questionurl->out(false, array('id' => $question->id)));
+        }
+    }
+}
+
+class question_bank_preview_action_column extends question_bank_action_column_base {
+    protected $strpreview;
+    protected $quizorcourseid;
+
+    public function __construct($quizorcourseid) {
+        parent::__construct();
+        $this->quizorcourseid = $quizorcourseid;
+        $this->stredit = get_string('preview');
+    }
+
+    protected function get_css_classes($question, $rowclasses) {
+        return 'previewaction';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (question_has_capability_on($question, 'use')) {
+            link_to_popup_window('/question/preview.php?id=' . $question->id .
+                    $this->quizorcourseid, 'questionpreview',
+                    ' <img src="' . $CFG->pixpath . '/t/preview.gif" class="iconsmall" alt="' . $this->strpreview . '" />',
+                    0, 0, $this->strpreview, QUESTION_PREVIEW_POPUP_OPTIONS);
+        }
+    }
+
+    public function get_required_fields() {
+        return array('q.id');
+    }
+}
+
+class question_bank_move_action_column extends question_bank_action_column_base {
+    protected $strmove;
+    protected $questionurl;
+
+    public function __construct($questionurl) {
+        parent::__construct();
+        $this->questionurl = $questionurl;
+        $this->strmove = get_string('move');
+    }
+
+    protected function get_css_classes($question, $rowclasses) {
+        return 'editaction';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (question_has_capability_on($question, 'move')) {
+            $this->print_icon('move', $this->strmove, $this->questionurl->out(false, array('id' => $question->id)));
+        }
+    }
+}
+
+/**
+ * action to delete (or hide) a question, or restore a previously hidden question.
+ */
+class question_bank_delete_action_column extends question_bank_action_column_base {
+    protected $strdelete;
+    protected $strrestore;
+    protected $questionurl;
+
+    public function __construct($questionurl) {
+        parent::__construct();
+        $this->questionurl = $questionurl;
+        $this->strdelete = get_string('delete');
+        $this->strrestore = get_string('restore');
+    }
+
+    protected function get_css_classes($question, $rowclasses) {
+        return 'deleteaction';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        if (question_has_capability_on($question, 'edit')) {
+            if ($question->hidden) {
+                $this->print_icon('restore', $this->strrestore, $pageurl->out(false, array('unhide' => $question->id)));
+            } else {
+                $this->print_icon('restore', $this->strrestore,
+                        $pageurl->out(false, array('deleteselected' => $question->id, 'q' . $question->id => 1)));
+            }
+        }
+    }
+
+    public function get_required_fields() {
+        return array('q.id', 'q.hidden');
+    }
+}
+
 /**
  * This class prints a view of the question bank, including
  *  + Some controls to allow users to to select what is displayed.