question bank: MDL-17871 refactor the code that displays particular information about each question into classes.

Work in progress. Most required classes are writted, but nothing uses them yet, and I have not dealt with column headers yet.
This commit is contained in:
tjhunt
2009-01-20 10:11:23 +00:00
parent 5138378ab3
commit 46795afcbd
+391
View 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.