/** * Moves a course into a category. * @param int $courseid the id of the course to move * @param int $categoryid the id of the target category to move the course to * @return bool success */ public static function update_course_category($courseid, $categoryid) { global $USER; $params = self::validate_parameters(self::update_course_category_parameters(), array('courseid' => $courseid, 'categoryid' => $categoryid)); $context = context_user::instance($USER->id); self::validate_context($context); if (!has_capability('local/webservice:local_ws_update_course_category', $context)) { throw new moodle_exception(nocapabilitytousethisservice); } if ($courseid == 1) { echo "Cannot move course 1 (site).\n"; throw new moodle_exception(cannotmovecourses); } echo "Moving course {$courseid} to category {$categoryid}.\n"; return move_courses(array($courseid), $categoryid); }
$courses = array(); foreach ($data as $key => $value) { if (preg_match('/^c\\d+$/', $key)) { $courseid = substr($key, 1); array_push($courses, $courseid); // check this course's category if ($movingcourse = $DB->get_record('course', array('id' => $courseid))) { if ($movingcourse->category != $id) { print_error('coursedoesnotbelongtocategory'); } } else { print_error('cannotfindcourse'); } } } move_courses($courses, $data->moveto); } /// Hide or show a course if ((!empty($hide) or !empty($show)) and confirm_sesskey()) { if (!empty($hide)) { $course = $DB->get_record('course', array('id' => $hide)); $visible = 0; } else { $course = $DB->get_record('course', array('id' => $show)); $visible = 1; } if ($course) { $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); require_capability('moodle/course:visibility', $coursecontext); $DB->set_field('course', 'visible', $visible, array('id' => $course->id)); $DB->set_field('course', 'visibleold', $visible, array('id' => $course->id));
/** * 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; }
/** * Test that triggering a course_updated event works as expected. */ public function test_course_updated_event() { global $DB; $this->resetAfterTest(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a category we are going to move this course to. $category = $this->getDataGenerator()->create_category(); // Create a hidden category we are going to move this course to. $categoryhidden = $this->getDataGenerator()->create_category(array('visible' => 0)); // Update course and catch course_updated event. $sink = $this->redirectEvents(); update_course($course); $events = $sink->get_events(); $sink->close(); // Get updated course information from the DB. $updatedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); // Validate event. $event = array_shift($events); $this->assertInstanceOf('\\core\\event\\course_updated', $event); $this->assertEquals('course', $event->objecttable); $this->assertEquals($updatedcourse->id, $event->objectid); $this->assertEquals(context_course::instance($course->id), $event->get_context()); $url = new moodle_url('/course/edit.php', array('id' => $event->objectid)); $this->assertEquals($url, $event->get_url()); $this->assertEquals($updatedcourse, $event->get_record_snapshot('course', $event->objectid)); $this->assertEquals('course_updated', $event->get_legacy_eventname()); $this->assertEventLegacyData($updatedcourse, $event); $expectedlog = array($updatedcourse->id, 'course', 'update', 'edit.php?id=' . $course->id, $course->id); $this->assertEventLegacyLogData($expectedlog, $event); // Move course and catch course_updated event. $sink = $this->redirectEvents(); move_courses(array($course->id), $category->id); $events = $sink->get_events(); $sink->close(); // Return the moved course information from the DB. $movedcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); // Validate event. $event = array_shift($events); $this->assertInstanceOf('\\core\\event\\course_updated', $event); $this->assertEquals('course', $event->objecttable); $this->assertEquals($movedcourse->id, $event->objectid); $this->assertEquals(context_course::instance($course->id), $event->get_context()); $this->assertEquals($movedcourse, $event->get_record_snapshot('course', $movedcourse->id)); $this->assertEquals('course_updated', $event->get_legacy_eventname()); $this->assertEventLegacyData($movedcourse, $event); $expectedlog = array($movedcourse->id, 'course', 'move', 'edit.php?id=' . $movedcourse->id, $movedcourse->id); $this->assertEventLegacyLogData($expectedlog, $event); // Move course to hidden category and catch course_updated event. $sink = $this->redirectEvents(); move_courses(array($course->id), $categoryhidden->id); $events = $sink->get_events(); $sink->close(); // Return the moved course information from the DB. $movedcoursehidden = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST); // Validate event. $event = array_shift($events); $this->assertInstanceOf('\\core\\event\\course_updated', $event); $this->assertEquals('course', $event->objecttable); $this->assertEquals($movedcoursehidden->id, $event->objectid); $this->assertEquals(context_course::instance($course->id), $event->get_context()); $this->assertEquals($movedcoursehidden, $event->get_record_snapshot('course', $movedcoursehidden->id)); $this->assertEquals('course_updated', $event->get_legacy_eventname()); $this->assertEventLegacyData($movedcoursehidden, $event); $expectedlog = array($movedcoursehidden->id, 'course', 'move', 'edit.php?id=' . $movedcoursehidden->id, $movedcoursehidden->id); $this->assertEventLegacyLogData($expectedlog, $event); $this->assertEventContextNotUsed($event); }
/** * 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; }
require_capability('moodle/course:create', context_coursecat::instance($moveto)); foreach ($data as $key => $value) { if (preg_match('/^c\\d+$/', $key)) { $courseid = substr($key, 1); // user must have category:manage and course:create capability for the course to be moved. $coursecontext = context_course::instance($courseid); foreach ($capabilities as $capability) { // Require capability here will result in a fatal error should the user not // have the requried category ensuring that no moves occur if they are // trying to move multiple courses. require_capability($capability, $coursecontext); array_push($courses, $courseid); } } } move_courses($courses, $moveto); } // get list of courses containing blocks if required if (!empty($blocklist) and confirm_sesskey()) { $blockname = $DB->get_field('block', 'name', array('id' => $blocklist)); $courses = array(); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$select} FROM {course} c\n {$join} JOIN {block_instances} bi ON bi.parentcontextid = ctx.id\n WHERE bi.blockname = ?"; $courses = $DB->get_records_sql($sql, array($blockname)); $totalcount = count($courses); // Keep only chunk of array which you want to display if ($totalcount > $perpage) { $courses = array_chunk($courses, $perpage, true); $courses = $courses[$page]; } foreach ($courses as $course) {
<?php /* * SELECT * FROM `mdl_context` WHERE `path` LIKE '/1/4862/4863%' and contextlevel=50 * */ define('CLI_SCRIPT', 1); require_once 'config.php'; require_once $CFG->dirroot . '/course/lib.php'; $sql = "SELECT * \n FROM {context} \n WHERE path LIKE '/1/4862/4863%' AND \n contextlevel=50"; $results = $DB->get_records_sql($sql); echo 'found ' . count($results) . ' records'; // build array of courseids to move $courses = array(); foreach ($results as $result) { $courses[] = $result->instanceid; } move_courses($courses, 66); echo 'Done!';
/** * Moves one or more courses out of the category they are currently in and into a new category. * * This function works much the same way as action_category_move_courses_into however it allows courses from multiple * categories to be moved into a single category. * * @param int|\coursecat $categoryorid The category to move them into. * @param array|int $courseids An array of course id's or optionally just a single course id. * @return bool True on success or false on failure. * @throws \moodle_exception */ public static function move_courses_into_category($categoryorid, $courseids = array()) { global $DB; if (!is_array($courseids)) { // Just a single course ID. $courseids = array($courseids); } // Bulk move courses from one category to another. if (count($courseids) === 0) { return false; } if ($categoryorid instanceof \coursecat) { $moveto = $categoryorid; } else { $moveto = \coursecat::get($categoryorid); } if (!$moveto->can_move_courses_out_of() || !$moveto->can_move_courses_into()) { throw new \moodle_exception('cannotmovecourses'); } list($where, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED); $sql = "SELECT c.id, c.category FROM {course} c WHERE c.id {$where}"; $courses = $DB->get_records_sql($sql, $params); $checks = array(); foreach ($courseids as $id) { if (!isset($courses[$id])) { throw new \moodle_exception('invalidcourseid'); } $catid = $courses[$id]->category; if (!isset($checks[$catid])) { $coursecat = \coursecat::get($catid); $checks[$catid] = $coursecat->can_move_courses_out_of() && $coursecat->can_move_courses_into(); } if (!$checks[$catid]) { throw new \moodle_exception('cannotmovecourses'); } } return \move_courses($courseids, $moveto->id); }
/** * 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; }