1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace qbank_managecategories; 18 19 use core\output\datafilter; 20 use core_question\local\bank\condition; 21 use core_question\local\bank\view; 22 23 /** 24 * This class controls from which category questions are listed. 25 * 26 * @package qbank_managecategories 27 * @copyright 2013 Ray Morris 28 * @author 2021 Safat Shahin <safatshahin@catalyst-au.net> 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 */ 31 class category_condition extends condition { 32 /** @var \stdClass The course record. */ 33 protected $course; 34 35 /** @var \stdClass The category record. */ 36 protected $category; 37 38 /** @var array of contexts. */ 39 protected $contexts; 40 41 /** @var string categoryID,contextID as used with question_bank_view->display(). */ 42 protected $cat; 43 44 /** @var int The maximum displayed length of the category info. */ 45 public $maxinfolength; 46 47 /** @var bool Include questions in subcategories of the specified category? */ 48 public $includesubcategories; 49 50 /** 51 * Constructor to initialize the category filter condition. 52 * 53 * @param view $qbank qbank view 54 */ 55 public function __construct(view $qbank = null) { 56 if (is_null($qbank)) { 57 return; 58 } 59 $this->cat = $qbank->get_pagevars('cat'); 60 $this->contexts = $qbank->contexts->having_one_edit_tab_cap($qbank->get_pagevars('tabname')); 61 $this->course = $qbank->course; 62 63 [$categoryid, $contextid] = self::validate_category_param($this->cat); 64 if (is_null($categoryid)) { 65 return; 66 } 67 68 $this->category = self::get_category_record($categoryid, $contextid); 69 70 parent::__construct($qbank); 71 $this->includesubcategories = $this->filter['filteroptions']['includesubcategories'] ?? false; 72 } 73 74 /** 75 * Return default category 76 * 77 * @return \stdClass default category 78 */ 79 public function get_default_category(): \stdClass { 80 if (empty($this->category)) { 81 return question_get_default_category(\context_course::instance($this->course->id)->id); 82 } 83 84 return $this->category; 85 } 86 87 public static function get_condition_key() { 88 return 'category'; 89 } 90 91 /** 92 * Returns course id. 93 * 94 * @return string Course id. 95 */ 96 public function get_course_id() { 97 return $this->course->id; 98 } 99 100 /** 101 * Called by question_bank_view to display the GUI for selecting a category 102 * @deprecated since Moodle 4.3 MDL-72321 - please do not use this function any more. 103 * @todo Final deprecation on Moodle 4.7 MDL-78090 104 */ 105 public function display_options() { 106 debugging('Function display_options() is deprecated, please use filtering objects', DEBUG_DEVELOPER); 107 global $PAGE; 108 $displaydata = []; 109 $catmenu = helper::question_category_options($this->contexts, true, 0, 110 true, -1, false); 111 $displaydata['categoryselect'] = \html_writer::select($catmenu, 'category', $this->cat, [], 112 array('class' => 'searchoptions custom-select', 'id' => 'id_selectacategory')); 113 $displaydata['categorydesc'] = ''; 114 if ($this->category) { 115 $displaydata['categorydesc'] = $this->print_category_info($this->category); 116 } 117 return $PAGE->get_renderer('qbank_managecategories')->render_category_condition($displaydata); 118 } 119 120 /** 121 * Displays the recursion checkbox GUI. 122 * question_bank_view places this within the section that is hidden by default 123 * @deprecated since Moodle 4.3 MDL-72321 - please do not use this function any more. 124 * @todo Final deprecation on Moodle 4.7 MDL-78090 125 */ 126 public function display_options_adv() { 127 debugging('Function display_options_adv() is deprecated, please use filtering objects', DEBUG_DEVELOPER); 128 global $PAGE; 129 $displaydata = []; 130 if ($this->recurse) { 131 $displaydata['checked'] = 'checked'; 132 } 133 return $PAGE->get_renderer('qbank_managecategories')->render_category_condition_advanced($displaydata); 134 } 135 136 /** 137 * Display the drop down to select the category. 138 * 139 * @param array $contexts of contexts that can be accessed from here. 140 * @param \moodle_url $pageurl the URL of this page. 141 * @param string $current 'categoryID,contextID'. 142 * @deprecated since Moodle 4.3 143 * @todo Final deprecation on Moodle 4.7 MDL-78090 144 */ 145 protected function display_category_form($contexts, $pageurl, $current) { 146 debugging( 147 'Function display_category_form() is deprecated, please use the core_question renderer instead.', 148 DEBUG_DEVELOPER 149 ); 150 echo \html_writer::start_div('choosecategory'); 151 $catmenu = question_category_options($contexts, true, 0, true, -1, false); 152 echo \html_writer::label(get_string('selectacategory', 'question'), 'id_selectacategory', true, ["class" => "mr-1"]); 153 echo \html_writer::select($catmenu, 'category', $current, [], 154 array('class' => 'searchoptions custom-select', 'id' => 'id_selectacategory')); 155 echo \html_writer::end_div() . "\n"; 156 } 157 158 /** 159 * Print the text if category id not available. 160 * @deprecated since Moodle 4.3 161 * @todo Final deprecation in Moodle 4.7 MDL-78090 162 */ 163 public static function print_choose_category_message(): void { 164 debugging( 165 'Function print_choose_category_message() is deprecated, please use ' . 166 'qbank_managecategories/choose_category template instead.', 167 DEBUG_DEVELOPER 168 ); 169 global $OUTPUT; 170 echo $OUTPUT->render_from_template('qbank_managecategories/choose_category', []); 171 } 172 173 /** 174 * Look up the category record based on category ID and context 175 * @param string $categoryandcontext categoryID,contextID as used with question_bank_view->display() 176 * @return \stdClass The category record 177 * @deprecated since Moodle 4.3 178 * @todo Final deprecation in Moodle 4.7 MDL-78090 179 */ 180 public static function get_current_category($categoryandcontext) { 181 debugging('Function get_current_category() is deprecated. Please do not use it anymore.', DEBUG_DEVELOPER); 182 global $DB, $OUTPUT; 183 [$categoryid, $contextid] = explode(',', $categoryandcontext); 184 if (!$categoryid) { 185 self::print_choose_category_message(); 186 return false; 187 } 188 189 if (!$category = $DB->get_record('question_categories', ['id' => $categoryid, 'contextid' => $contextid])) { 190 echo $OUTPUT->box_start('generalbox questionbank'); 191 echo $OUTPUT->notification('Category not found!'); 192 echo $OUTPUT->box_end(); 193 return false; 194 } 195 196 return $category; 197 } 198 199 /** 200 * Return category and context ID from compound parameter. 201 * 202 * @param string $categoryandcontext Comma-separated list of category and context IDs. 203 * @return int[]|null[] 204 */ 205 public static function validate_category_param(string $categoryandcontext): array { 206 [$categoryid, $contextid] = explode(',', $categoryandcontext); 207 if (!$categoryid) { 208 return [null, null]; 209 } 210 return [clean_param($categoryid, PARAM_INT), clean_param($contextid, PARAM_INT)]; 211 } 212 213 /** 214 * Fetch the question category record matching the provided category and context IDs. 215 * 216 * @param int $categoryid 217 * @param int $contextid 218 * @return \stdClass 219 * @throws \dml_exception 220 */ 221 public static function get_category_record($categoryid, $contextid): \stdClass { 222 global $DB; 223 return $DB->get_record('question_categories', 224 ['id' => $categoryid, 'contextid' => $contextid], 225 '*', 226 MUST_EXIST); 227 } 228 229 /** 230 * Print the category description 231 * @param \stdClass $category the category information form the database. 232 * @deprecated since Moodle 4.3 MDL-72321 - please do not use this function any more. 233 * @todo Final deprecation on Moodle 4.7 MDL-78090 234 */ 235 protected function print_category_info($category): string { 236 debugging('Function print_category_info() is deprecated. Please do not use it anymore', DEBUG_DEVELOPER); 237 $formatoptions = new \stdClass(); 238 $formatoptions->noclean = true; 239 $formatoptions->overflowdiv = true; 240 if (isset($this->maxinfolength)) { 241 return shorten_text(format_text($category->info, $category->infoformat, $formatoptions, $this->course->id), 242 $this->maxinfolength); 243 } 244 245 return format_text($category->info, $category->infoformat, $formatoptions, $this->course->id); 246 } 247 248 public static function build_query_from_filter(array $filter): array { 249 global $DB; 250 $recursive = false; 251 if (isset($filter['filteroptions']['includesubcategories'])) { 252 $recursive = (bool)$filter['filteroptions']['includesubcategories']; 253 } 254 255 // Sub categories. 256 if ($recursive) { 257 $categories = $filter['values']; 258 $categoriesandsubcategories = []; 259 foreach ($categories as $categoryid) { 260 $categoriesandsubcategories += question_categorylist($categoryid); 261 } 262 } else { 263 $categoriesandsubcategories = $filter['values']; 264 } 265 266 $jointype = $filter['jointype'] ?? self::JOINTYPE_DEFAULT; 267 $equal = !($jointype === datafilter::JOINTYPE_NONE); 268 [$insql, $params] = $DB->get_in_or_equal($categoriesandsubcategories, SQL_PARAMS_NAMED, 'cat', $equal); 269 $where = 'qbe.questioncategoryid ' . $insql; 270 return [$where, $params]; 271 } 272 273 public function get_title() { 274 return get_string('category', 'core_question'); 275 } 276 277 public function get_filter_class() { 278 return 'qbank_managecategories/datafilter/filtertypes/categories'; 279 } 280 281 public function allow_custom() { 282 return false; 283 } 284 285 public function allow_multiple() { 286 return false; 287 } 288 289 public function allow_empty() { 290 return false; 291 } 292 293 public function get_join_list(): array { 294 return [ 295 datafilter::JOINTYPE_ANY, 296 ]; 297 } 298 299 public function get_initial_values() { 300 $catmenu = helper::question_category_options($this->contexts, true, 0, true, -1, false); 301 $values = []; 302 foreach ($catmenu as $menu) { 303 foreach ($menu as $heading => $catlist) { 304 $values[] = (object) [ 305 // Add a list item for each question category context. This will serve as a "heading" within the list 306 // and we will use CSS to disable pointer events so it cannot be selected. 307 'value' => '', 308 'title' => $heading, 309 'disabled' => true, 310 ]; 311 foreach ($catlist as $key => $value) { 312 $values[] = (object) [ 313 // Remove contextid from value. 314 'value' => str_contains($key, ',') ? substr($key, 0, strpos($key, ',')) : $key, 315 'title' => $value, 316 'selected' => ($key === $this->cat), 317 ]; 318 } 319 } 320 } 321 return $values; 322 } 323 324 public function get_filteroptions(): \stdClass { 325 return (object)[ 326 'includesubcategories' => $this->includesubcategories, 327 ]; 328 } 329 330 public function is_required(): bool { 331 return true; 332 } 333 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body