Skip to content

Commit

Permalink
MDL-40313 questionbank: Add question filtering API
Browse files Browse the repository at this point in the history
Add new API for filtering questions, refactoring the options to display
old questions and include subcategories into new
question_bank_search_condition classes. Make the new API pluggable via
local_[pluginname]_get_question_bank_search_conditions.
  • Loading branch information
sensei-hacker authored and timhunt committed Jan 9, 2014
1 parent bbb291b commit efa5155
Show file tree
Hide file tree
Showing 13 changed files with 476 additions and 47 deletions.
1 change: 1 addition & 0 deletions lang/en/question.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
$string['addmorechoiceblanks'] = 'Blanks for {no} more choices';
$string['addcategory'] = 'Add category';
$string['adminreport'] = 'Report on possible problems in your question database.';
$string['advancedsearchoptions'] = 'Search options';
$string['answers'] = 'Answers';
$string['availableq'] = 'Available?';
$string['badbase'] = 'Bad base before **: {$a}**';
Expand Down
46 changes: 37 additions & 9 deletions mod/quiz/editlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,7 @@ class quiz_question_bank_view extends question_bank_view {
protected $quizhasattempts = false;
/** @var object the quiz settings. */
protected $quiz = false;
const MAX_TEXT_LENGTH = 200;

/**
* Constructor
Expand Down Expand Up @@ -1184,29 +1185,34 @@ public function display($tabname, $page, $perpage, $cat,
return;
}

// Display the current category.
if (!$category = $this->get_current_category($cat)) {
return;
}
$this->print_category_info($category);
$editcontexts = $this->contexts->having_one_edit_tab_cap($tabname);
array_unshift($this->searchconditions,
new question_bank_search_condition_hide(!$showhidden));
array_unshift($this->searchconditions,
new question_bank_search_condition_category($cat, $recurse,
$editcontexts, $this->baseurl, $this->course, self::MAX_TEXT_LENGTH));

echo $OUTPUT->box_start('generalbox questionbank');

$this->display_category_form($this->contexts->having_one_edit_tab_cap($tabname),
$this->baseurl, $cat);
$this->display_options_form($showquestiontext);

// Continues with list of questions.
$this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname),
$this->baseurl, $cat, $this->cm, $recurse, $page,
$perpage, $showhidden, $showquestiontext,
$this->contexts->having_cap('moodle/question:add'));

$this->display_options($recurse, $showhidden, $showquestiontext);
echo $OUTPUT->box_end();
}

/**
* prints a form to choose categories
* @deprecated since Moodle 2.6 MDL-40313.
* @see question_bank_search_condition_category
* @todo MDL-41978 This will be deleted in Moodle 2.8
*/
protected function print_choose_category_message($categoryandcontext) {
global $OUTPUT;
debugging('print_choose_category_message() is deprecated, please use question_bank_search_condition_category instead.', DEBUG_DEVELOPER);
echo $OUTPUT->box_start('generalbox questionbank');
$this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'),
$this->baseurl, $categoryandcontext);
Expand All @@ -1216,6 +1222,27 @@ protected function print_choose_category_message($categoryandcontext) {
echo $OUTPUT->box_end();
}

/**
* Display the form with options for which questions are displayed and how they are displayed.
* This differs from parent display_options_form only in that it does not have the checkbox to show the question text.
* @param bool $showquestiontext Display the text of the question within the list. (Currently ignored)
*/
protected function display_options_form($showquestiontext) {
global $PAGE;
echo html_writer::start_tag('form', array('method' => 'get',
'action' => new moodle_url('/mod/quiz/edit.php'), 'id' => 'displayoptions'));
echo html_writer::start_div();
foreach ($this->searchconditions as $searchcondition) {
echo $searchcondition->display_options($this);
}
$this->display_advanced_search_form();
$go = html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('go')));
echo html_writer::tag('noscript', html_writer::tag('div', $go), array('class' => 'inline'));
echo html_writer::end_div();
echo html_writer::end_tag('form');
$PAGE->requires->yui_module('moodle-question-searchform', 'M.question.searchform.init');
}

protected function print_category_info($category) {
$formatoptions = new stdClass();
$formatoptions->noclean = true;
Expand All @@ -1232,6 +1259,7 @@ protected function print_category_info($category) {
}

protected function display_options($recurse, $showhidden, $showquestiontext) {
debugging('display_options() is deprecated, see display_options_form() instead.', DEBUG_DEVELOPER);
echo '<form method="get" action="edit.php" id="displayoptions">';
echo "<fieldset class='invisiblefieldset'>";
echo html_writer::input_hidden_params($this->baseurl,
Expand Down
39 changes: 39 additions & 0 deletions question/classes/bank_search_condition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/**
* An abstract class for filtering/searching questions.
* See also init_search_conditions
*/
abstract class core_question_bank_search_condition {
/**
* @return string An SQL fragment to be ANDed into the WHERE clause to filter which questions are shown
*/
public abstract function where();

/**
* @return array Parameters to be bound to the above WHERE clause fragment
*/
public function params() {
return array();
}

/**
* Display GUI for selecting criteria for this condition. Displayed when Show More is open.
*
* Compare display_options(), which displays always, whether Show More is open or not.
* @return string HTML form fragment
*/
public function display_options_adv() {
return;
}

/**
* Display GUI for selecting criteria for this condition. Displayed always, whether Show More is open or not.
*
* Compare display_options_adv(), which displays when Show More is open.
* @return string HTML form fragment
*/
public function display_options() {
return;
}
}
146 changes: 146 additions & 0 deletions question/classes/bank_search_condition_category.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php
/**
* This class controls from which category questions are listed.
*
* @package moodlecore
* @subpackage questionbank
* @copyright 2013 Tim Hunt, Ray Morris and others {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_question_bank_search_condition_category extends core_question_bank_search_condition {
protected $category;
protected $recurse;
protected $where;
protected $params;
protected $cat;

/**
* Constructor
* @param string $cat categoryID,contextID as used with question_bank_view->display()
* @param boolean $recurse Whether to include questions from sub-categories
* @param array $contexts Context objects as used by question_category_options()
* @param moodle_url $baseurl The URL the form is submitted to
* @param stdClass $course Course record
* @param integer $maxinfolength The maximum displayed length of the category info
*/
public function __construct($cat = null, $recurse = false, $contexts, $baseurl, $course, $maxinfolength = null) {
$this->cat = $cat;
$this->recurse = $recurse;
$this->contexts = $contexts;
$this->baseurl = $baseurl;
$this->course = $course;
$this->init();
$this->maxinfolength = $maxinfolength;
}

/**
* Initialize the object so it will be ready to return where() and params()
*/
private function init() {
global $DB;
if (!$this->category = $this->get_current_category($this->cat)) {
return;
}
if ($this->recurse) {
$categoryids = question_categorylist($this->category->id);
} else {
$categoryids = array($this->category->id);
}
list($catidtest, $this->params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'cat');
$this->where = 'q.category ' . $catidtest;
}

/**
* @returns string SQL fragment to be ANDed to the where clause to select which category of questions to display
*/
public function where() {
return $this->where;
}

/**
* @returns array Parameters to be bound to the SQL query to select which category of questions to display
*/
public function params() {
return $this->params;
}

/**
* Called by question_bank_view to display the GUI for selecting a category
*/
public function display_options() {
$this->display_category_form($this->contexts, $this->baseurl, $this->cat);
$this->print_category_info($this->category);
}

/**
* Displays the recursion checkbox GUI.
* question_bank_view places this within the section that is hidden by default
*/
public function display_options_adv() {
echo '<div>';
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'recurse',
'value' => 0, 'id' => 'recurse_off'));
echo html_writer::checkbox('recurse', '1', $this->recurse, get_string('includesubcategories', 'question'),
array('id' => 'recurse_on', 'class' => 'searchoptions'));
echo "</div>\n";

}

/**
* Display the drop down to select the category
*/
protected function display_category_form($contexts, $pageurl, $current) {
global $OUTPUT;

echo '<div class="choosecategory">';
$catmenu = question_category_options($contexts, false, 0, true);
$select = new single_select($this->baseurl, 'category', $catmenu, $current, null, 'catmenu');
$select->set_label(get_string('selectacategory', 'question'));
echo $OUTPUT->render($select);
echo "</div>\n";

}

/**
* Look up the category record based on cateogry ID and context
* @param string $categoryandcontext categoryID,contextID as used with question_bank_view->display()
* @return stdClass The category record
*/
protected function get_current_category($categoryandcontext) {
global $DB, $OUTPUT;
list($categoryid, $contextid) = explode(',', $categoryandcontext);
if (!$categoryid) {
$this->print_choose_category_message($categoryandcontext);
return false;
}

if (!$category = $DB->get_record('question_categories',
array('id' => $categoryid, 'contextid' => $contextid))) {
echo $OUTPUT->box_start('generalbox questionbank');
echo $OUTPUT->notification('Category not found!');
echo $OUTPUT->box_end();
return false;
}

return $category;
}

/**
* Print the category description
*/
protected function print_category_info($category) {
$formatoptions = new stdClass();
$formatoptions->noclean = true;
$formatoptions->overflowdiv = true;
echo '<div class="boxaligncenter categoryinfo">';
if (isset($this->maxinfolength)) {
echo shorten_text(format_text($category->info, $category->infoformat, $formatoptions, $this->course->id),
$this->maxinfolength);
} else {
echo format_text($category->info, $category->infoformat, $formatoptions, $this->course->id);
}
echo "</div>\n";
}

}

37 changes: 37 additions & 0 deletions question/classes/bank_search_condition_hide.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
/**
* This class controls whether hidden / deleted questions are hidden in the list.
*/
class core_question_bank_search_condition_hide extends core_question_bank_search_condition {
protected $where = '';
protected $hide;

/**
* @param bool $hide include old "deleted" questions.
*/
public function __construct($hide = true) {
$this->hide = $hide;
if ($hide) {
$this->where = 'q.hidden = 0';
}
}

/**
* @return string An SQL fragment to be ANDed into the WHERE clause to show or hide deleted/hidden questions
*/
public function where() {
return $this->where;
}

/**
* Print HTML to display the "Also show old questions" checkbox
*/
public function display_options_adv() {
echo "<div>";
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'showhidden',
'value' => '0', 'id' => 'showhidden_off'));
echo html_writer::checkbox('showhidden', '1', (! $this->hide), get_string('showhidden', 'question'),
array('id' => 'showhidden_on', 'class' => 'searchoptions'));
echo "</div>\n";
}
}
Loading

0 comments on commit efa5155

Please sign in to comment.