libdir/listlib.php"); class question_category_list extends moodle_list { var $table = "question_categories"; var $listitemclassname = 'question_category_list_item'; function question_category_list($type='ul', $attributes='', $editable = false, $page = 0){ parent::moodle_list($type, $attributes, $editable, $page); } function get_records() { global $COURSE, $CFG; $categories = get_records($this->table, 'course', "{$COURSE->id}", $this->sortby); $catids = array_keys($categories); $select = "WHERE category IN ('".join("', '", $catids)."') AND hidden='0' AND parent='0'"; $questioncounts = get_records_sql_menu('SELECT category, COUNT(*) FROM '. $CFG->prefix . 'question' .' '. $select.' GROUP BY category'); foreach ($categories as $categoryid => $category){ if (isset($questioncounts[$categoryid])){ $categories[$categoryid]->questioncount = $questioncounts[$categoryid]; } else { $categories[$categoryid]->questioncount = 0; } } $this->records = $categories; } } class question_category_list_item extends list_item { function item_html($extraargs = array()){ global $CFG; $pixpath = $CFG->pixpath; $str = $extraargs['str']; $category = $this->item; $linkcss = $category->publish ? ' class="published" ' : ' class="unpublished" '; if (!empty($parent->page)) { $pagelink="&page=".$parent->page; } else { $pagelink=""; } /// Each section adds html to be displayed as part of this list item $item = ' ' .$str->edit. ' ' . $category->name . '('.$category->questioncount.')'. ''; $item .= ' '. $category->info; if (!empty($category->publish)) { $item .= ' ' .$str->hide. ' '; } else { $item .= ' ' .$str->publish. ' '; } if ($category->id != $extraargs['defaultcategory']->id) { $item .= ' ' .$str->delete. ' '; } return $item; } } /** * Class representing question categories * * @package questionbank */ class question_category_object { var $str; var $pixpath; /** * Nested list to display categories. * * @var question_category_list */ var $editlist; var $newtable; var $tab; var $tabsize = 3; var $categories; var $categorystrings; var $defaultcategory; /** * Constructor * * Gets necessary strings and sets relevant path information */ function question_category_object($page) { global $CFG, $COURSE; $this->tab = str_repeat(' ', $this->tabsize); $this->str->course = get_string('course'); $this->str->category = get_string('category', 'quiz'); $this->str->categoryinfo = get_string('categoryinfo', 'quiz'); $this->str->questions = get_string('questions', 'quiz'); $this->str->add = get_string('add'); $this->str->delete = get_string('delete'); $this->str->moveup = get_string('moveup'); $this->str->movedown = get_string('movedown'); $this->str->edit = get_string('editthiscategory'); $this->str->hide = get_string('hide'); $this->str->publish = get_string('publish', 'quiz'); $this->str->order = get_string('order'); $this->str->parent = get_string('parent', 'quiz'); $this->str->add = get_string('add'); $this->str->action = get_string('action'); $this->str->top = get_string('top', 'quiz'); $this->str->addcategory = get_string('addcategory', 'quiz'); $this->str->editcategory = get_string('editcategory', 'quiz'); $this->str->cancel = get_string('cancel'); $this->str->editcategories = get_string('editcategories', 'quiz'); $this->str->page = get_string('page'); $this->pixpath = $CFG->pixpath; $this->editlist = new question_category_list('ul', '', true, $page); $this->editlist->add_page_params(array('id'=>$COURSE->id)); $this->initialize(); } /** * Displays the user interface * */ function display_user_interface() { /// Interface for editing existing categories print_heading_with_help($this->str->editcategories, 'categories', 'quiz'); $this->output_edit_list(); echo '
'; /// Interface for adding a new category: print_heading_with_help($this->str->addcategory, 'categories_edit', 'quiz'); $this->output_new_table(); echo '
'; } /** * Initializes this classes general category-related variables */ function initialize() { global $COURSE, $CFG; /// Get the existing categories if (!$this->defaultcategory = get_default_question_category($COURSE->id)) { error("Error: Could not find or make a category!"); } $this->editlist->list_from_records(QUESTION_PAGE_LENGTH); $this->categories = $this->editlist->records; // create the array of id=>full_name strings $this->categorystrings = $this->expanded_category_strings($this->categories); } /** * Outputs a table to allow entry of a new category */ function output_new_table() { global $USER, $COURSE; $publishoptions[0] = get_string("no"); $publishoptions[1] = get_string("yes"); $this->newtable->head = array ($this->str->parent, $this->str->category, $this->str->categoryinfo, $this->str->publish, $this->str->action); $this->newtable->width = '200'; $this->newtable->data[] = array(); $this->newtable->tablealign = 'center'; /// Each section below adds a data cell to the table row $viableparents[0] = $this->str->top; $viableparents = $viableparents + $this->categorystrings; $this->newtable->align['parent'] = "left"; $this->newtable->wrap['parent'] = "nowrap"; $row['parent'] = choose_from_menu ($viableparents, "newparent", $this->str->top, "", "", "", true); $this->newtable->align['category'] = "left"; $this->newtable->wrap['category'] = "nowrap"; $row['category'] = ''; $this->newtable->align['info'] = "left"; $this->newtable->wrap['info'] = "nowrap"; $row['info'] = ''; $this->newtable->align['publish'] = "left"; $this->newtable->wrap['publish'] = "nowrap"; $row['publish'] = choose_from_menu ($publishoptions, "newpublish", "", "", "", "", true); $this->newtable->align['action'] = "left"; $this->newtable->wrap['action'] = "nowrap"; $row['action'] = ''; $this->newtable->data[] = $row; // wrap the table in a form and output it echo '
'; echo '
'; echo "sesskey\" />"; echo ''; echo ''; print_table($this->newtable); echo '
'; echo '
'; } /** * Outputs a list to allow editing/rearranging of existing categories * * $this->initialize() must have already been called * * @param int $page page to display (0=do not paginate) */ function output_edit_list() { print_box_start('boxwidthwide boxaligncenter generalbox'); echo $this->editlist->to_html(0, array('str'=>$this->str, 'defaultcategory' => $this->defaultcategory)); print_box_end(); echo $this->editlist->display_page_numbers(); } /** * gets all the courseids for the given categories * * @param array categories contains category objects in a tree representation * @return array courseids flat array in form categoryid=>courseid */ function get_course_ids($categories) { $courseids = array(); foreach ($categories as $key=>$cat) { $courseids[$key] = $cat->course; if (!empty($cat->children)) { $courseids = array_merge($courseids, $this->get_course_ids($cat->children)); } } return $courseids; } function edit_single_category($categoryid, $page=1) { /// Interface for adding a new category global $USER, $COURSE; /// Interface for editing existing categories if ($category = get_record("question_categories", "id", $categoryid)) { echo '

'; echo $this->str->edit; helpbutton("categories_edit", $this->str->editcategory, "quiz"); echo '

'; echo '
'; $this->output_edit_single_table($category, $page); echo '
'; echo '

'; print_footer($COURSE); exit; } else { error("Category $categoryid not found", "category.php?id={$COURSE->id}"); } } /** * Outputs a table to allow editing of an existing category * * @param object category * @param int page current page */ function output_edit_single_table($category, $page=1) { global $USER, $COURSE; $publishoptions[0] = get_string("no"); $publishoptions[1] = get_string("yes"); $strupdate = get_string('update'); $edittable = new stdClass; $edittable->head = array ($this->str->parent, $this->str->category, $this->str->categoryinfo, $this->str->publish, $this->str->action); $edittable->width = 200; $edittable->data[] = array(); $edittable->tablealign = 'center'; /// Each section below adds a data cell to the table row $viableparents = $this->categorystrings; $this->set_viable_parents($viableparents, $category); $viableparents = array(0=>$this->str->top) + $viableparents; $edittable->align['parent'] = "left"; $edittable->wrap['parent'] = "nowrap"; $row['parent'] = choose_from_menu ($viableparents, "updateparent", "{$category->parent}", "", "", "", true); $edittable->align['category'] = "left"; $edittable->wrap['category'] = "nowrap"; $row['category'] = ''; $edittable->align['info'] = "left"; $edittable->wrap['info'] = "nowrap"; $row['info'] = ''; $edittable->align['publish'] = "left"; $edittable->wrap['publish'] = "nowrap"; $selected = (boolean)$category->publish ? 1 : 0; $row['publish'] = choose_from_menu ($publishoptions, "updatepublish", $selected, "", "", "", true); $edittable->align['action'] = "left"; $edittable->wrap['action'] = "nowrap"; $row['action'] = ''; $edittable->data[] = $row; // wrap the table in a form and output it echo '

'; echo '
'; echo "sesskey\" />"; echo ''; echo ''; echo ""; print_table($edittable); echo '
'; echo '

'; } /** * Creates an array of "full-path" category strings * Structure: * key => string * where key is the category id, and string contains the name of all ancestors as well as the particular category name * E.g. '123'=>'Language / English / Grammar / Modal Verbs" * * @param array $categories an array containing categories arranged in a tree structure */ function expanded_category_strings($categories, $parent=null) { $prefix = is_null($parent) ? '' : "$parent / "; $categorystrings = array(); foreach ($categories as $key => $category) { $expandedname = "$prefix$category->name"; $categorystrings[$key] = $expandedname; if (isset($category->children)) { $categorystrings = $categorystrings + $this->expanded_category_strings($category->children, $expandedname); } } return $categorystrings; } /** * Sets the viable parents * * Viable parents are any except for the category itself, or any of it's descendants * The parentstrings parameter is passed by reference and changed by this function. * * @param array parentstrings a list of parentstrings * @param object category */ function set_viable_parents(&$parentstrings, $category) { unset($parentstrings[$category->id]); if (isset($category->children)) { foreach ($category->children as $child) { $this->set_viable_parents($parentstrings, $child); } } } /** * Gets question categories * * @param int parent - if given, restrict records to those with this parent id. * @param string sort - [[sortfield [,sortfield]] {ASC|DESC}] * @return array categories */ function get_question_categories($parent=null, $sort="sortorder ASC") { global $COURSE; if (is_null($parent)) { $categories = get_records('question_categories', 'course', "{$COURSE->id}", $sort); } else { $select = "parent = '$parent' AND course = '{$COURSE->id}'"; $categories = get_records_select('question_categories', $select, $sort); } return $categories; } /** * Deletes an existing question category * * @param int deletecat id of category to delete * @param int destcategoryid id of category which will inherit the orphans of deletecat */ function delete_category($deletecat, $destcategoryid = null) { global $USER, $COURSE; if (!$category = get_record("question_categories", "id", $deletecat)) { // security error("No such category $deletecat!", "category.php?id={$COURSE->id}"); } if (!is_null($destcategoryid)) { // Need to move some questions before deleting the category if (!$category2 = get_record("question_categories", "id", $destcategoryid)) { // security error("No such category $destcategoryid!", "category.php?id={$COURSE->id}"); } if (! set_field('question', 'category', $destcategoryid, 'category', $deletecat)) { error("Error while moving questions from category '" . format_string($category->name) . "' to '$category2->name'", "category.php?id={$COURSE->id}"); } } else { // todo: delete any hidden questions that are not actually in use any more if ($count = count_records("question", "category", $category->id)) { $vars = new stdClass; $vars->name = $category->name; $vars->count = $count; print_simple_box(get_string("categorymove", "quiz", $vars), "center"); $this->initialize(); $categorystrings = $this->categorystrings; unset ($categorystrings[$category->id]); echo "

"; echo '
'; echo "sesskey\" />"; echo "id}\" />"; echo "id\" />"; choose_from_menu($categorystrings, "confirm", "", ""); echo ""; echo "str->cancel}\" />"; echo '
'; echo "

"; print_footer($COURSE); exit; } } /// Send the children categories to live with their grandparent if ($childcats = get_records("question_categories", "parent", $category->id)) { foreach ($childcats as $childcat) { if (! set_field("question_categories", "parent", $category->parent, "id", $childcat->id)) { error("Could not update a child category!", "category.php?id={$COURSE->id}"); } } } /// Finally delete the category itself if (delete_records("question_categories", "id", $category->id)) { notify(get_string("categorydeleted", "quiz", format_string($category->name)), 'notifysuccess'); } } /** * Moves a category up or down in the display order * * @param string direction up|down * @param int categoryid id of category to move */ function move_category_up_down ($direction, $categoryid) { /// Move a category up or down $swapcategory = NULL; $movecategory = NULL; if ($direction == 'up') { if ($movecategory = get_record("question_categories", "id", $categoryid)) { $categories = $this->get_question_categories("$movecategory->parent", 'parent, sortorder, name'); foreach ($categories as $category) { if ($category->id == $movecategory->id) { break; } $swapcategory = $category; } } } if ($direction == 'down') { if ($movecategory = get_record("question_categories", "id", $categoryid)) { $categories = $this->get_question_categories("$movecategory->parent", 'parent, sortorder, name'); $choosenext = false; foreach ($categories as $category) { if ($choosenext) { $swapcategory = $category; break; } if ($category->id == $movecategory->id) { $choosenext = true; } } } } if ($swapcategory and $movecategory) { // Renumber everything for robustness $count=0; foreach ($categories as $category) { $count++; if ($category->id == $swapcategory->id) { $category = $movecategory; } else if ($category->id == $movecategory->id) { $category = $swapcategory; } if (! set_field("question_categories", "sortorder", $count, "id", $category->id)) { notify("Could not update that category!"); } } } } /** * Changes the parent of a category * * @param int categoryid * @param int parentid */ function move_category($categoryid, $parentid) { /// Move a category to a new parent if ($tempcat = get_record("question_categories", "id", $categoryid)) { if ($tempcat->parent != $parentid) { if (! set_field("question_categories", "parent", $parentid, "id", $tempcat->id)) { notify("Could not update that category!"); } } } } /** * Changes the published status of a category * * @param boolean publish * @param int categoryid */ function publish_category($publish, $categoryid) { /// Hide or publish a category $publish = ($publish == false) ? 0 : 1; $tempcat = get_record("question_categories", "id", $categoryid); if ($tempcat) { if (! set_field("question_categories", "publish", $publish, "id", $tempcat->id)) { notify("Could not update that category!"); } } } /** * Creates a new category with given params * * @param int $newparent id of the parent category * @param string $newcategory the name for the new category * @param string $newinfo the info field for the new category * @param int $newpublish whether to publish the category * @param int $newcourse the id of the associated course */ function add_category($newparent, $newcategory, $newinfo, $newpublish, $newcourse) { if (empty($newcategory)) { notify(get_string('categorynamecantbeblank', 'quiz'), 'notifyproblem'); return false; } if ($newparent) { // first check that the parent category is in the correct course if(!(get_field('question_categories', 'course', 'id', $newparent) == $newcourse)) { return false; } } $cat = NULL; $cat->parent = $newparent; $cat->name = $newcategory; $cat->info = $newinfo; $cat->publish = $newpublish; $cat->course = $newcourse; $cat->sortorder = 999; $cat->stamp = make_unique_id_code(); if (!insert_record("question_categories", $cat)) { error("Could not insert the new question category '$newcategory'", "category.php?id={$newcourse}"); } else { notify(get_string("categoryadded", "quiz", $newcategory), 'notifysuccess'); } } /** * Updates an existing category with given params * * @param int updateid * @param int updateparent * @param string updatename * @param string updateinfo * @param int updatepublish * @param int courseid the id of the associated course */ function update_category($updateid, $updateparent, $updatename, $updateinfo, $updatepublish, $courseid) { if (empty($updatename)) { notify(get_string('categorynamecantbeblank', 'quiz'), 'notifyproblem'); return false; } $cat = NULL; $cat->id = $updateid; $cat->parent = $updateparent; $cat->name = $updatename; $cat->info = $updateinfo; $cat->publish = $updatepublish; if (!update_record("question_categories", $cat)) { error("Could not update the category '$updatename'", "category.php?id={$courseid}"); } else { notify(get_string("categoryupdated", 'quiz'), 'notifysuccess'); } } } ?>