| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: category_class.php,v 1.32.2.7 2008/09/05 03:38:17 tjhunt Exp $ 2 /** 3 * Class representing question categories 4 * 5 * @author Martin Dougiamas and many others. {@link http://moodle.org} 6 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 7 * @package questionbank 8 */ 9 10 // number of categories to display on page 11 define("QUESTION_PAGE_LENGTH", 25); 12 13 require_once("$CFG->libdir/listlib.php"); 14 require_once("$CFG->dirroot/question/category_form.php"); 15 require_once ('move_form.php'); 16 17 class question_category_list extends moodle_list { 18 var $table = "question_categories"; 19 var $listitemclassname = 'question_category_list_item'; 20 /** 21 * @var reference to list displayed below this one. 22 */ 23 var $nextlist = null; 24 /** 25 * @var reference to list displayed above this one. 26 */ 27 var $lastlist = null; 28 29 var $context = null; 30 31 function question_category_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null){ 32 parent::moodle_list('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage); 33 $this->context = $context; 34 } 35 36 function get_records() { 37 $this->records = get_categories_for_contexts($this->context->id, $this->sortby); 38 } 39 function process_actions($left, $right, $moveup, $movedown, $moveupcontext, $movedowncontext, $tocontext){ 40 global $CFG; 41 //parent::procces_actions redirects after any action 42 parent::process_actions($left, $right, $moveup, $movedown); 43 if ($tocontext == $this->context->id){ 44 //only called on toplevel list 45 if ($moveupcontext){ 46 $cattomove = $moveupcontext; 47 $totop = 0; 48 } elseif ($movedowncontext){ 49 $cattomove = $movedowncontext; 50 $totop = 1; 51 } 52 $toparent = "0,{$this->context->id}"; 53 redirect($CFG->wwwroot.'/question/contextmove.php?'. 54 $this->pageurl->get_query_string(compact('cattomove', 'totop', 'toparent'))); 55 } 56 } 57 } 58 59 class question_category_list_item extends list_item { 60 61 62 function set_icon_html($first, $last, &$lastitem){ 63 global $CFG; 64 $category = $this->item; 65 $this->icons['edit']= $this->image_icon(get_string('editthiscategory'), 66 "{$CFG->wwwroot}/question/category.php?".$this->parentlist->pageurl->get_query_string(array('edit'=>$category->id)), 'edit'); 67 parent::set_icon_html($first, $last, $lastitem); 68 $toplevel = ($this->parentlist->parentitem === null);//this is a top level item 69 if (($this->parentlist->nextlist !== null) && $last && $toplevel && (count($this->parentlist->items)>1)){ 70 $this->icons['down'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->nextlist->context)), 71 $this->parentlist->pageurl->out_action(array('movedowncontext'=>$this->id, 'tocontext'=>$this->parentlist->nextlist->context->id)), 'down'); 72 } 73 if (($this->parentlist->lastlist !== null) && $first && $toplevel && (count($this->parentlist->items)>1)){ 74 $this->icons['up'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->lastlist->context)), 75 $this->parentlist->pageurl->out_action(array('moveupcontext'=>$this->id, 'tocontext'=>$this->parentlist->lastlist->context->id)), 'up'); 76 } 77 } 78 function item_html($extraargs = array()){ 79 global $CFG; 80 $pixpath = $CFG->pixpath; 81 $str = $extraargs['str']; 82 $category = $this->item; 83 84 $editqestions = get_string('editquestions', 'quiz'); 85 86 /// Each section adds html to be displayed as part of this list item 87 $questionbankurl = "{$CFG->wwwroot}/question/edit.php?". 88 $this->parentlist->pageurl->get_query_string(array('category'=>"$category->id,$category->contextid")); 89 $catediturl = $this->parentlist->pageurl->out(false, array('edit'=>$this->id)); 90 $item = "<b><a title=\"{$str->edit}\" href=\"$catediturl\">".$category->name ."</a></b> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>'; 91 92 $item .= ' '. $category->info; 93 94 if (count($this->parentlist->records)!=1){ // don't allow delete if this is the last category in this context. 95 $item .= '<a title="' . $str->delete . '" href="'.$this->parentlist->pageurl->out_action(array('delete'=>$this->id)).'"> 96 <img src="' . $pixpath . '/t/delete.gif" class="iconsmall" alt="' .$str->delete. '" /></a>'; 97 } 98 99 return $item; 100 } 101 102 } 103 104 105 /** 106 * Class representing question categories 107 * 108 * @package questionbank 109 */ 110 class question_category_object { 111 112 var $str; 113 var $pixpath; 114 /** 115 * Nested lists to display categories. 116 * 117 * @var array 118 */ 119 var $editlists = array(); 120 var $newtable; 121 var $tab; 122 var $tabsize = 3; 123 //------------------------------------------------------ 124 /** 125 * @var moodle_url Object representing url for this page 126 */ 127 var $pageurl; 128 /** 129 * @var question_category_edit_form Object representing form for adding / editing categories. 130 */ 131 var $catform; 132 133 /** 134 * Constructor 135 * 136 * Gets necessary strings and sets relevant path information 137 */ 138 function question_category_object($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) { 139 global $CFG, $COURSE; 140 141 $this->tab = str_repeat(' ', $this->tabsize); 142 143 $this->str->course = get_string('course'); 144 $this->str->category = get_string('category', 'quiz'); 145 $this->str->categoryinfo = get_string('categoryinfo', 'quiz'); 146 $this->str->questions = get_string('questions', 'quiz'); 147 $this->str->add = get_string('add'); 148 $this->str->delete = get_string('delete'); 149 $this->str->moveup = get_string('moveup'); 150 $this->str->movedown = get_string('movedown'); 151 $this->str->edit = get_string('editthiscategory'); 152 $this->str->hide = get_string('hide'); 153 $this->str->publish = get_string('publish', 'quiz'); 154 $this->str->order = get_string('order'); 155 $this->str->parent = get_string('parent', 'quiz'); 156 $this->str->add = get_string('add'); 157 $this->str->action = get_string('action'); 158 $this->str->top = get_string('top', 'quiz'); 159 $this->str->addcategory = get_string('addcategory', 'quiz'); 160 $this->str->editcategory = get_string('editcategory', 'quiz'); 161 $this->str->cancel = get_string('cancel'); 162 $this->str->editcategories = get_string('editcategories', 'quiz'); 163 $this->str->page = get_string('page'); 164 $this->pixpath = $CFG->pixpath; 165 166 $this->pageurl = $pageurl; 167 168 $this->initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts); 169 170 } 171 172 173 174 /** 175 * Initializes this classes general category-related variables 176 */ 177 function initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) { 178 $lastlist = null; 179 foreach ($contexts as $context){ 180 $this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context); 181 $this->editlists[$context->id]->lastlist =& $lastlist; 182 if ($lastlist!== null){ 183 $lastlist->nextlist =& $this->editlists[$context->id]; 184 } 185 $lastlist =& $this->editlists[$context->id]; 186 } 187 188 $count = 1; 189 $paged = false; 190 foreach ($this->editlists as $key => $list){ 191 list($paged, $count) = $this->editlists[$key]->list_from_records($paged, $count); 192 } 193 $this->catform = new question_category_edit_form($this->pageurl, compact('contexts', 'currentcat')); 194 if (!$currentcat){ 195 $this->catform->set_data(array('parent'=>$defaultcategory)); 196 } 197 } 198 /** 199 * Displays the user interface 200 * 201 */ 202 function display_user_interface() { 203 204 /// Interface for editing existing categories 205 $this->output_edit_lists(); 206 207 208 echo '<br />'; 209 /// Interface for adding a new category: 210 $this->output_new_table(); 211 echo '<br />'; 212 213 } 214 215 /** 216 * Outputs a table to allow entry of a new category 217 */ 218 function output_new_table() { 219 $this->catform->display(); 220 } 221 222 223 /** 224 * Outputs a list to allow editing/rearranging of existing categories 225 * 226 * $this->initialize() must have already been called 227 * 228 */ 229 function output_edit_lists() { 230 print_heading_with_help(get_string('editcategories', 'quiz'), 'categories', 'question'); 231 foreach ($this->editlists as $context => $list){ 232 $listhtml = $list->to_html(0, array('str'=>$this->str)); 233 if ($listhtml){ 234 print_box_start('boxwidthwide boxaligncenter generalbox questioncategories contextlevel' . $list->context->contextlevel); 235 print_heading(get_string('questioncatsfor', 'question', print_context_name(get_context_instance_by_id($context))), '', 3); 236 echo $listhtml; 237 print_box_end(); 238 } 239 } 240 echo $list->display_page_numbers(); 241 } 242 243 244 245 /** 246 * gets all the courseids for the given categories 247 * 248 * @param array categories contains category objects in a tree representation 249 * @return array courseids flat array in form categoryid=>courseid 250 */ 251 function get_course_ids($categories) { 252 $courseids = array(); 253 foreach ($categories as $key=>$cat) { 254 $courseids[$key] = $cat->course; 255 if (!empty($cat->children)) { 256 $courseids = array_merge($courseids, $this->get_course_ids($cat->children)); 257 } 258 } 259 return $courseids; 260 } 261 262 263 264 function edit_single_category($categoryid) { 265 /// Interface for adding a new category 266 global $COURSE; 267 /// Interface for editing existing categories 268 if ($category = get_record("question_categories", "id", $categoryid)) { 269 270 $category->parent = "$category->parent,$category->contextid"; 271 $category->submitbutton = get_string('savechanges'); 272 $category->categoryheader = $this->str->edit; 273 $this->catform->set_data($category); 274 $this->catform->display(); 275 } else { 276 error("Category $categoryid not found"); 277 } 278 } 279 280 281 /** 282 * Sets the viable parents 283 * 284 * Viable parents are any except for the category itself, or any of it's descendants 285 * The parentstrings parameter is passed by reference and changed by this function. 286 * 287 * @param array parentstrings a list of parentstrings 288 * @param object category 289 */ 290 function set_viable_parents(&$parentstrings, $category) { 291 292 unset($parentstrings[$category->id]); 293 if (isset($category->children)) { 294 foreach ($category->children as $child) { 295 $this->set_viable_parents($parentstrings, $child); 296 } 297 } 298 } 299 300 /** 301 * Gets question categories 302 * 303 * @param int parent - if given, restrict records to those with this parent id. 304 * @param string sort - [[sortfield [,sortfield]] {ASC|DESC}] 305 * @return array categories 306 */ 307 function get_question_categories($parent=null, $sort="sortorder ASC") { 308 global $COURSE; 309 if (is_null($parent)) { 310 $categories = get_records('question_categories', 'course', "{$COURSE->id}", $sort); 311 } else { 312 $select = "parent = '$parent' AND course = '{$COURSE->id}'"; 313 $categories = get_records_select('question_categories', $select, $sort); 314 } 315 return $categories; 316 } 317 318 /** 319 * Deletes an existing question category 320 * 321 * @param int deletecat id of category to delete 322 */ 323 function delete_category($categoryid) { 324 global $CFG; 325 question_can_delete_cat($categoryid); 326 if (!$category = get_record("question_categories", "id", $categoryid)) { // security 327 error("No such category $cat!", $this->pageurl->out()); 328 } 329 /// Send the children categories to live with their grandparent 330 if (!set_field("question_categories", "parent", $category->parent, "parent", $category->id)) { 331 error("Could not update a child category!", $this->pageurl->out()); 332 } 333 334 /// Finally delete the category itself 335 if (delete_records("question_categories", "id", $category->id)) { 336 notify(get_string("categorydeleted", "quiz", format_string($category->name)), 'notifysuccess'); 337 redirect($this->pageurl->out());//always redirect after successful action 338 } 339 } 340 function move_questions_and_delete_category($oldcat, $newcat){ 341 question_can_delete_cat($oldcat); 342 $this->move_questions($oldcat, $newcat); 343 $this->delete_category($oldcat); 344 } 345 346 function display_move_form($questionsincategory, $category){ 347 $vars = new stdClass; 348 $vars->name = $category->name; 349 $vars->count = $questionsincategory; 350 print_simple_box(get_string("categorymove", "quiz", $vars), "center"); 351 $this->moveform->display(); 352 } 353 354 function move_questions($oldcat, $newcat){ 355 $questionids = get_records_select_menu('question', "category = $oldcat AND (parent = 0 OR parent = id)", '', 'id,1'); 356 if (!question_move_questions_to_category(implode(',', array_keys($questionids)), $newcat)) { 357 print_error('errormovingquestions', 'question', $returnurl, $ids); 358 } 359 } 360 361 /** 362 * Creates a new category with given params 363 * 364 */ 365 function add_category($newparent, $newcategory, $newinfo) { 366 if (empty($newcategory)) { 367 print_error('categorynamecantbeblank', 'quiz'); 368 } 369 list($parentid, $contextid) = explode(',', $newparent); 370 //moodle_form makes sure select element output is legal no need for further cleaning 371 require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid)); 372 373 if ($parentid) { 374 if(!(get_field('question_categories', 'contextid', 'id', $parentid) == $contextid)) { 375 error("Could not insert the new question category '$newcategory' illegal contextid '$contextid'."); 376 } 377 } 378 379 $cat = new object(); 380 $cat->parent = $parentid; 381 $cat->contextid = $contextid; 382 $cat->name = $newcategory; 383 $cat->info = $newinfo; 384 $cat->sortorder = 999; 385 $cat->stamp = make_unique_id_code(); 386 if (!insert_record("question_categories", $cat)) { 387 error("Could not insert the new question category '$newcategory'"); 388 } else { 389 redirect($this->pageurl->out());//always redirect after successful action 390 } 391 } 392 393 /** 394 * Updates an existing category with given params 395 * 396 */ 397 function update_category($updateid, $newparent, $newname, $newinfo) { 398 global $CFG, $QTYPES; 399 if (empty($newname)) { 400 print_error('categorynamecantbeblank', 'quiz'); 401 } 402 403 list($parentid, $tocontextid) = explode(',', $newparent); 404 405 $oldcat = get_record('question_categories', 'id', $updateid); 406 $fromcontext = get_context_instance_by_id($oldcat->contextid); 407 require_capability('moodle/question:managecategory', $fromcontext); 408 if ($oldcat->contextid == $tocontextid){ 409 $tocontext = get_context_instance_by_id($tocontextid); 410 require_capability('moodle/question:managecategory', $tocontext); 411 } 412 $cat = NULL; 413 $cat->id = $updateid; 414 $cat->name = $newname; 415 $cat->info = $newinfo; 416 //never move category where it is the default 417 if (1 != count_records_sql("SELECT count(*) FROM {$CFG->prefix}question_categories c1, {$CFG->prefix}question_categories c2 WHERE c2.id = $updateid AND c1.contextid = c2.contextid")){ 418 // If the question name has changed, rename any random questions in that category. 419 if (addslashes($oldcat->name) != $cat->name) { 420 $randomqname = $QTYPES[RANDOM]->question_name($cat); 421 set_field('question', 'name', addslashes($randomqname), 'category', $cat->id, 'qtype', RANDOM); 422 // Ignore errors here. It is not a big deal if the questions are not renamed. 423 } 424 425 // Then update the category itself. 426 if ($oldcat->contextid == $tocontextid){ // not moving contexts 427 $cat->parent = $parentid; 428 if (!update_record("question_categories", $cat)) { 429 error("Could not update the category '$newname'", $this->pageurl->out()); 430 } else { 431 redirect($this->pageurl->out()); 432 } 433 } else { 434 if (!update_record("question_categories", $cat)) { 435 error("Could not update the category '$newname'", $this->pageurl->out()); 436 } else { 437 redirect($CFG->wwwroot.'/question/contextmove.php?'. 438 $this->pageurl->get_query_string(array('cattomove' => $updateid, 439 'toparent'=>$newparent))); 440 } 441 } 442 } else { 443 error("Cannot move the category '$newname'. It is the last in this context.", $this->pageurl->out()); 444 } 445 } 446 447 function move_question_from_cat_confirm($fromcat, $fromcourse, $tocat=null, $question=null){ 448 global $QTYPES; 449 if (!$question){ 450 $questions[] = $question; 451 } else { 452 $questions = get_records('question', 'category', $tocat->id); 453 } 454 $urls = array(); 455 foreach ($questions as $question){ 456 $urls = array_merge($urls, $QTYPES[$question->qtype]->find_file_links_in_question($question)); 457 } 458 if ($fromcourse){ 459 $append = 'tocourse'; 460 } else { 461 $append = 'tosite'; 462 } 463 if ($tocat){ 464 echo '<p>'.get_string('needtomovethesefilesincat','question').'</p>'; 465 } else { 466 echo '<p>'.get_string('needtomovethesefilesinquestion','question').'</p>'; 467 } 468 } 469 470 471 472 473 } 474 475 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |