/** * This function tests the question_delete_course_category function. * * @param bool $feedback Whether to return feedback * @dataProvider provider_feedback */ public function test_question_delete_course_category($feedback) { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); // Test that the feedback works. if ($feedback) { $this->expectOutputRegex('|' . get_string('unusedcategorydeleted', 'question') . '|'); } question_delete_course_category($category, 0, $feedback); // Verify category deleted. $criteria = array('id' => $qcat->id); $this->assertEquals(0, $DB->count_records('question_categories', $criteria)); // Verify questions deleted or moved. $criteria = array('category' => $qcat->id); $this->assertEquals(0, $DB->count_records('question', $criteria)); }
/** * Delete category, but move contents to another category. * @param object $ccategory * @param int $newparentid category id * @return bool status */ function category_delete_move($category, $newparentid, $showfeedback = true) { global $CFG, $DB, $OUTPUT; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->dirroot . '/cohort/lib.php'; if (!($newparentcat = $DB->get_record('course_categories', array('id' => $newparentid)))) { return false; } if ($children = $DB->get_records('course_categories', array('parent' => $category->id), 'sortorder ASC')) { foreach ($children as $childcat) { move_category($childcat, $newparentcat); } } if ($courses = $DB->get_records('course', array('category' => $category->id), 'sortorder ASC', 'id')) { if (!move_courses(array_keys($courses), $newparentid)) { echo $OUTPUT->notification("Error moving courses"); return false; } echo $OUTPUT->notification(get_string('coursesmovedout', '', format_string($category->name)), 'notifysuccess'); } // move or delete cohorts in this context cohort_delete_category($category); // now delete anything that may depend on course category context grade_course_category_delete($category->id, $newparentid, $showfeedback); if (!question_delete_course_category($category, $newparentcat, $showfeedback)) { echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $category), 'notifysuccess'); return false; } // finally delete the category and it's context $DB->delete_records('course_categories', array('id' => $category->id)); delete_context(CONTEXT_COURSECAT, $category->id); events_trigger('course_category_deleted', $category); echo $OUTPUT->notification(get_string('coursecategorydeleted', '', format_string($category->name)), 'notifysuccess'); return true; }
/** * Deletes a category and moves all content (children, courses and questions) to the new parent * * Note that this function does not check capabilities, {@link coursecat::can_move_content_to()} * must be called prior * * @param int $newparentid * @param bool $showfeedback * @return bool */ public function delete_move($newparentid, $showfeedback = false) { global $CFG, $DB, $OUTPUT; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->dirroot . '/cohort/lib.php'; // Get all objects and lists because later the caches will be reset so. // We don't need to make extra queries. $newparentcat = self::get($newparentid, MUST_EXIST, true); $catname = $this->get_formatted_name(); $children = $this->get_children(); $params = array('category' => $this->id); $coursesids = $DB->get_fieldset_select('course', 'id', 'category = :category ORDER BY sortorder ASC', $params); $context = $this->get_context(); if ($children) { foreach ($children as $childcat) { $childcat->change_parent_raw($newparentcat); // Log action. $event = \core\event\course_category_updated::create(array('objectid' => $childcat->id, 'context' => $childcat->get_context())); $event->set_legacy_logdata(array(SITEID, 'category', 'move', 'editcategory.php?id=' . $childcat->id, $childcat->id)); $event->trigger(); } fix_course_sortorder(); } if ($coursesids) { if (!move_courses($coursesids, $newparentid)) { if ($showfeedback) { echo $OUTPUT->notification("Error moving courses"); } return false; } if ($showfeedback) { echo $OUTPUT->notification(get_string('coursesmovedout', '', $catname), 'notifysuccess'); } } // Move or delete cohorts in this context. cohort_delete_category($this); // Now delete anything that may depend on course category context. grade_course_category_delete($this->id, $newparentid, $showfeedback); if (!question_delete_course_category($this, $newparentcat, $showfeedback)) { if ($showfeedback) { echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $catname), 'notifysuccess'); } return false; } // Finally delete the category and it's context. $DB->delete_records('course_categories', array('id' => $this->id)); $context->delete(); // Trigger a course category deleted event. /* @var \core\event\course_category_deleted $event */ $event = \core\event\course_category_deleted::create(array('objectid' => $this->id, 'context' => $context, 'other' => array('name' => $this->name))); $event->set_coursecat($this); $event->trigger(); cache_helper::purge_by_event('changesincoursecat'); if ($showfeedback) { echo $OUTPUT->notification(get_string('coursecategorydeleted', '', $catname), 'notifysuccess'); } // If we deleted $CFG->defaultrequestcategory, make it point somewhere else. if ($this->id == $CFG->defaultrequestcategory) { set_config('defaultrequestcategory', $DB->get_field('course_categories', 'MIN(id)', array('parent' => 0))); } return true; }
/** * Deletes a category and moves all content (children, courses and questions) to the new parent * * Note that this function does not check capabilities, {@link coursecat::can_move_content_to()} * must be called prior * * @param int $newparentid * @param bool $showfeedback * @return bool */ public function delete_move($newparentid, $showfeedback = false) { global $CFG, $DB, $OUTPUT; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->dirroot . '/cohort/lib.php'; // get all objects and lists because later the caches will be reset so // we don't need to make extra queries $newparentcat = self::get($newparentid, MUST_EXIST, true); $catname = $this->get_formatted_name(); $children = $this->get_children(); $coursesids = $DB->get_fieldset_select('course', 'id', 'category = :category ORDER BY sortorder ASC', array('category' => $this->id)); $context = context_coursecat::instance($this->id); if ($children) { foreach ($children as $childcat) { $childcat->change_parent_raw($newparentcat); // Log action. add_to_log(SITEID, "category", "move", "editcategory.php?id={$childcat->id}", $childcat->id); } fix_course_sortorder(); } if ($coursesids) { if (!move_courses($coursesids, $newparentid)) { if ($showfeedback) { echo $OUTPUT->notification("Error moving courses"); } return false; } if ($showfeedback) { echo $OUTPUT->notification(get_string('coursesmovedout', '', $catname), 'notifysuccess'); } } // move or delete cohorts in this context cohort_delete_category($this); // now delete anything that may depend on course category context grade_course_category_delete($this->id, $newparentid, $showfeedback); if (!question_delete_course_category($this, $newparentcat, $showfeedback)) { if ($showfeedback) { echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $catname), 'notifysuccess'); } return false; } // finally delete the category and it's context $DB->delete_records('course_categories', array('id' => $this->id)); $context->delete(); add_to_log(SITEID, "category", "delete", "index.php", "{$this->name} (ID {$this->id})"); events_trigger('course_category_deleted', $this); cache_helper::purge_by_event('changesincoursecat'); if ($showfeedback) { echo $OUTPUT->notification(get_string('coursecategorydeleted', '', $catname), 'notifysuccess'); } // If we deleted $CFG->defaultrequestcategory, make it point somewhere else. if ($this->id == $CFG->defaultrequestcategory) { set_config('defaultrequestcategory', $DB->get_field('course_categories', 'MIN(id)', array('parent' => 0))); } return true; }
/** * Delete category, but move contents to another category. * @param object $ccategory * @param int $newparentid category id * @return bool status */ function category_delete_move($category, $newparentid, $showfeedback = true) { global $CFG; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/questionlib.php'; if (!($newparentcat = get_record('course_categories', 'id', $newparentid))) { return false; } if ($children = get_records('course_categories', 'parent', $category->id, 'sortorder ASC')) { foreach ($children as $childcat) { if (!move_category($childcat, $newparentcat)) { notify("Error moving category {$childcat->name}"); return false; } } } if ($courses = get_records('course', 'category', $category->id, 'sortorder ASC', 'id')) { if (!move_courses(array_keys($courses), $newparentid)) { notify("Error moving courses"); return false; } notify(get_string('coursesmovedout', '', format_string($category->name)), 'notifysuccess'); } // now delete anything that may depend on course category context grade_course_category_delete($category->id, $newparentid, $showfeedback); if (!question_delete_course_category($category, $newparentcat, $showfeedback)) { notify(get_string('errordeletingquestionsfromcategory', 'question', $category), 'notifysuccess'); return false; } // finally delete the category and it's context delete_records('course_categories', 'id', $category->id); delete_context(CONTEXT_COURSECAT, $category->id); events_trigger('course_category_deleted', $category); notify(get_string('coursecategorydeleted', '', format_string($category->name)), 'notifysuccess'); return true; }
/** * This function tests that the functions responsible for moving questions to * different contexts also updates the tag instances associated with the questions. */ public function test_altering_tag_instance_context() { global $CFG, $DB; // Set to admin user. $this->setAdminUser(); // Create two course categories - we are going to delete one of these later and will expect // all the questions belonging to the course in the deleted category to be moved. $coursecat1 = $this->getDataGenerator()->create_category(); $coursecat2 = $this->getDataGenerator()->create_category(); // Create a couple of categories and questions. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $questioncat1 = $questiongenerator->create_question_category(array('contextid' => context_coursecat::instance($coursecat1->id)->id)); $questioncat2 = $questiongenerator->create_question_category(array('contextid' => context_coursecat::instance($coursecat2->id)->id)); $question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id)); $question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat1->id)); $question3 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id)); $question4 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat2->id)); // Now lets tag these questions. tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat1->contextid); tag_set('question', $question2->id, array('tag 3', 'tag 4'), 'core_question', $questioncat1->contextid); tag_set('question', $question3->id, array('tag 5', 'tag 6'), 'core_question', $questioncat2->contextid); tag_set('question', $question4->id, array('tag 7', 'tag 8'), 'core_question', $questioncat2->contextid); // Test moving the questions to another category. question_move_questions_to_category(array($question1->id, $question2->id), $questioncat2->id); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Test moving them back. question_move_questions_to_category(array($question1->id, $question2->id), $questioncat1->id); // Test that all tag_instances are now reset to how they were initially. $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat1->contextid))); $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now test moving a whole question category to another context. question_move_category_to_context($questioncat1->id, $questioncat1->contextid, $questioncat2->contextid); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now test moving them back. question_move_category_to_context($questioncat1->id, $questioncat2->contextid, context_coursecat::instance($coursecat1->id)->id); // Test that all tag_instances are now reset to how they were initially. $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat1->contextid))); $this->assertEquals(4, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Now we want to test deleting the course category and moving the questions to another category. question_delete_course_category($coursecat1, $coursecat2, false); // Test that all tag_instances belong to one context. $this->assertEquals(8, $DB->count_records('tag_instance', array('component' => 'core_question', 'contextid' => $questioncat2->contextid))); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create some question categories and questions in this course. $questioncat = $questiongenerator->create_question_category(array('contextid' => context_course::instance($course->id)->id)); $question1 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id)); $question2 = $questiongenerator->create_question('shortanswer', null, array('category' => $questioncat->id)); // Add some tags to these questions. tag_set('question', $question1->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid); tag_set('question', $question2->id, array('tag 1', 'tag 2'), 'core_question', $questioncat->contextid); // Create a course that we are going to restore the other course to. $course2 = $this->getDataGenerator()->create_course(); // Create backup file and save it to the backup location. $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2); $bc->execute_plan(); $results = $bc->get_results(); $file = $results['backup_destination']; $fp = get_file_packer(); $filepath = $CFG->dataroot . '/temp/backup/test-restore-course'; $file->extract_to_pathname($fp, $filepath); $bc->destroy(); unset($bc); // Now restore the course. $rc = new restore_controller('test-restore-course', $course2->id, backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2, backup::TARGET_NEW_COURSE); $rc->execute_precheck(); $rc->execute_plan(); // Get the created question category. $restoredcategory = $DB->get_record('question_categories', array('contextid' => context_course::instance($course2->id)->id), '*', MUST_EXIST); // Check that there are two questions in the restored to course's context. $this->assertEquals(2, $DB->count_records('question', array('category' => $restoredcategory->id))); }