// Attempt to update the grade item if relevant $grademodule = $DB->get_record($cm->modname, array('id' => $cm->instance)); $grademodule->cmidnumber = $cm->idnumber; $grademodule->modname = $cm->modname; grade_update_mod_grades($grademodule); // We need to return strings after they've been through filters for multilang $stringoptions = new stdClass(); $stringoptions->context = $coursecontext; echo json_encode(array('instancename' => html_entity_decode(format_string($module->name, true, $stringoptions)))); break; } break; case 'course': switch ($field) { case 'marker': require_capability('moodle/course:setcurrentsection', $coursecontext); course_set_marker($course->id, $value); break; } break; } break; case 'DELETE': switch ($class) { case 'resource': require_capability('moodle/course:manageactivities', $modcontext); course_delete_module($cm->id); break; } break; }
/** * Deletes a section * * Do not call this function directly, instead call {@link course_delete_section()} * * @param int|stdClass|section_info $section * @param bool $forcedeleteifnotempty if set to false section will not be deleted if it has modules in it. * @return bool whether section was deleted */ public function delete_section($section, $forcedeleteifnotempty = false) { global $DB; if (!$this->uses_sections()) { // Not possible to delete section if sections are not used. return false; } if (!is_object($section)) { $section = $DB->get_record('course_sections', array('course' => $this->get_courseid(), 'section' => $section), 'id,section,sequence,summary'); } if (!$section || !$section->section) { // Not possible to delete 0-section. return false; } if (!$forcedeleteifnotempty && (!empty($section->sequence) || !empty($section->summary))) { return false; } $course = $this->get_course(); // Remove the marker if it points to this section. if ($section->section == $course->marker) { course_set_marker($course->id, 0); } $lastsection = $DB->get_field_sql('SELECT max(section) from {course_sections} WHERE course = ?', array($course->id)); // Find out if we need to descrease the 'numsections' property later. $courseformathasnumsections = array_key_exists('numsections', $this->get_format_options()); $decreasenumsections = $courseformathasnumsections && $section->section <= $course->numsections; // Move the section to the end. move_section_to($course, $section->section, $lastsection, true); // Delete all modules from the section. foreach (preg_split('/,/', $section->sequence, -1, PREG_SPLIT_NO_EMPTY) as $cmid) { course_delete_module($cmid); } // Delete section and it's format options. $DB->delete_records('course_format_options', array('sectionid' => $section->id)); $DB->delete_records('course_sections', array('id' => $section->id)); rebuild_course_cache($course->id, true); // Descrease 'numsections' if needed. if ($decreasenumsections) { $this->update_course_format_options(array('numsections' => $course->numsections - 1)); } return true; }
/** * Moves a section within a course, from a position to another. * Be very careful: $section and $destination refer to section number, * not id!. * * @param object $course * @param int $section Section number (not id!!!) * @param int $destination * @return boolean Result */ function move_section_to($course, $section, $destination) { /// Moves a whole course section up and down within the course global $USER, $DB; if (!$destination && $destination != 0) { return true; } if ($destination > $course->numsections) { return false; } // Get all sections for this course and re-order them (2 of them should now share the same section number) if (!($sections = $DB->get_records_menu('course_sections', array('course' => $course->id), 'section ASC, id ASC', 'id, section'))) { return false; } $movedsections = reorder_sections($sections, $section, $destination); // Update all sections. Do this in 2 steps to avoid breaking database // uniqueness constraint $transaction = $DB->start_delegated_transaction(); foreach ($movedsections as $id => $position) { if ($sections[$id] !== $position) { $DB->set_field('course_sections', 'section', -$position, array('id' => $id)); } } foreach ($movedsections as $id => $position) { if ($sections[$id] !== $position) { $DB->set_field('course_sections', 'section', $position, array('id' => $id)); } } // Adjust destination to reflect the actual section $moveup = false; if ($section > $destination) { $destination++; $moveup = true; } // If we move the highlighted section itself, then just highlight the destination. // Adjust the higlighted section location if we move something over it either direction. if ($section == $course->marker) { course_set_marker($course, $destination); } elseif ($moveup && $section > $course->marker && $course->marker >= $destination) { course_set_marker($course, $course->marker + 1); } elseif (!$moveup && $section < $course->marker && $course->marker <= $destination) { course_set_marker($course, $course->marker - 1); } // if the focus is on the section that is being moved, then move the focus along if (course_get_display($course->id) == $section) { course_set_display($course->id, $destination); } $transaction->allow_commit(); return true; }
/** * Moves section to the specified position * * @param int|section_info $section * @param int|section_info $parent * @param null|int|section_info $before * @return int new section number */ protected function move_section($section, $parent, $before = null) { global $DB; $section = $this->get_section($section); $parent = $this->get_section($parent); $newsectionnumber = $section->section; if (!$this->can_move_section_to($section, $parent, $before)) { return $newsectionnumber; } if ($section->visible != $parent->visible && $section->parent != $parent->section) { // section is changing parent and new parent has different visibility than the section if ($section->visible) { // visible section is moved under hidden parent $updatesectionvisible = 0; $updatesectionvisibleold = 1; } else { // hidden section is moved under visible parent if ($section->visibleold) { $updatesectionvisible = 1; $updatesectionvisibleold = 1; } } } // find the changes in the sections numbering $origorder = array(); foreach ($this->get_sections() as $subsection) { $origorder[$subsection->id] = $subsection->section; } $neworder = array(); $this->reorder_sections($neworder, 0, $section->section, $parent, $before); if (count($origorder) != count($neworder)) { die('Error in sections hierarchy'); // TODO } $changes = array(); foreach ($origorder as $id => $num) { if ($num == $section->section) { $newsectionnumber = $neworder[$id]; } if ($num != $neworder[$id]) { $changes[$id] = array('old' => $num, 'new' => $neworder[$id]); if ($num && $this->get_course()->marker == $num) { $changemarker = $neworder[$id]; } } if ($this->get_section_number($parent) === $num) { $newparentnum = $neworder[$id]; } } if (empty($changes) && $newparentnum == $section->parent) { return $newsectionnumber; } // build array of required changes in field 'parent' // $changeparent[sectionid] = newsectionnum; $changeparent = array(); foreach ($this->get_sections() as $subsection) { foreach ($changes as $id => $change) { if ($subsection->parent == $change['old']) { $changeparent[$subsection->id] = $change['new']; } } } $changeparent[$section->id] = $newparentnum; // Update all in database in one transaction $transaction = $DB->start_delegated_transaction(); // Update sections numbers in 2 steps to avoid breaking database uniqueness constraint foreach ($changes as $id => $change) { $DB->set_field('course_sections', 'section', -$change['new'], array('id' => $id)); } foreach ($changes as $id => $change) { $DB->set_field('course_sections', 'section', $change['new'], array('id' => $id)); } // change parents of their subsections foreach ($changeparent as $id => $newnum) { $this->update_section_format_options(array('id' => $id, 'parent' => $newnum)); } $transaction->allow_commit(); rebuild_course_cache($this->courseid, true); if (isset($changemarker)) { course_set_marker($this->courseid, $changemarker); } if (isset($updatesectionvisible)) { $this->set_section_visible($newsectionnumber, $updatesectionvisible, $updatesectionvisibleold); } return $newsectionnumber; }
/** * Moves a section within a course, from a position to another. * Be very careful: $section and $destination refer to section number, * not id!. * * @param object $course * @param int $section Section number (not id!!!) * @param int $destination * @return boolean Result */ function move_section_to($course, $section, $destination) { /// Moves a whole course section up and down within the course global $USER, $DB; if (!$destination && $destination != 0) { return true; } // compartibility with course formats using field 'numsections' $courseformatoptions = course_get_format($course)->get_format_options(); if (array_key_exists('numsections', $courseformatoptions) && $destination > $courseformatoptions['numsections'] || $destination < 1) { return false; } // Get all sections for this course and re-order them (2 of them should now share the same section number) if (!($sections = $DB->get_records_menu('course_sections', array('course' => $course->id), 'section ASC, id ASC', 'id, section'))) { return false; } $movedsections = reorder_sections($sections, $section, $destination); // Update all sections. Do this in 2 steps to avoid breaking database // uniqueness constraint $transaction = $DB->start_delegated_transaction(); foreach ($movedsections as $id => $position) { if ($sections[$id] !== $position) { $DB->set_field('course_sections', 'section', -$position, array('id' => $id)); } } foreach ($movedsections as $id => $position) { if ($sections[$id] !== $position) { $DB->set_field('course_sections', 'section', $position, array('id' => $id)); } } // If we move the highlighted section itself, then just highlight the destination. // Adjust the higlighted section location if we move something over it either direction. if ($section == $course->marker) { course_set_marker($course->id, $destination); } elseif ($section > $course->marker && $course->marker >= $destination) { course_set_marker($course->id, $course->marker + 1); } elseif ($section < $course->marker && $course->marker <= $destination) { course_set_marker($course->id, $course->marker - 1); } $transaction->allow_commit(); rebuild_course_cache($course->id, true); return true; }
// It is based of the "topics" format defined('MOODLE_INTERNAL') || die; require_once $CFG->libdir . '/filelib.php'; require_once $CFG->libdir . '/completionlib.php'; // Horrible backwards compatible parameter aliasing.. if ($topic = optional_param('topic', 0, PARAM_INT)) { $url = $PAGE->url; $url->param('section', $topic); debugging('Outdated topic param passed to course/view.php', DEBUG_DEVELOPER); redirect($url); } // End backwards-compatible aliasing.. $context = context_course::instance($course->id); if ($marker >= 0 && has_capability('moodle/course:setcurrentsection', $context) && confirm_sesskey()) { $course->marker = $marker; course_set_marker($course->id, $marker); } // make sure all sections are created $course = course_get_format($course)->get_course(); course_create_sections_if_missing($course, range(0, $course->numsections)); //onetopic format is always multipage $course->realcoursedisplay = $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE; $course->coursedisplay = COURSE_DISPLAY_MULTIPAGE; $renderer = $PAGE->get_renderer('format_onetopic'); $section = optional_param('section', -1, PARAM_INT); if (isset($section) && $section >= 0 && $course->numsections >= $section) { $USER->display[$course->id] = $section; $displaysection = $section; } else { if (isset($USER->display[$course->id]) && $course->numsections >= $USER->display[$course->id]) { $displaysection = $USER->display[$course->id];
public function test_course_delete_section() { global $DB; $this->resetAfterTest(true); $generator = $this->getDataGenerator(); $course = $generator->create_course(array('numsections' => 6, 'format' => 'topics'), array('createsections' => true)); $assign0 = $generator->create_module('assign', array('course' => $course, 'section' => 0)); $assign1 = $generator->create_module('assign', array('course' => $course, 'section' => 1)); $assign21 = $generator->create_module('assign', array('course' => $course, 'section' => 2)); $assign22 = $generator->create_module('assign', array('course' => $course, 'section' => 2)); $assign3 = $generator->create_module('assign', array('course' => $course, 'section' => 3)); $assign5 = $generator->create_module('assign', array('course' => $course, 'section' => 5)); $assign6 = $generator->create_module('assign', array('course' => $course, 'section' => 6)); $this->setAdminUser(); // Attempt to delete non-existing section. $this->assertFalse(course_delete_section($course, 10, false)); $this->assertFalse(course_delete_section($course, 9, true)); // Attempt to delete 0-section. $this->assertFalse(course_delete_section($course, 0, true)); $this->assertTrue($DB->record_exists('course_modules', array('id' => $assign0->cmid))); // Delete last section. $this->assertTrue(course_delete_section($course, 6, true)); $this->assertFalse($DB->record_exists('course_modules', array('id' => $assign6->cmid))); $this->assertEquals(5, course_get_format($course)->get_course()->numsections); // Delete empty section. $this->assertTrue(course_delete_section($course, 4, false)); $this->assertEquals(4, course_get_format($course)->get_course()->numsections); // Delete section in the middle (2). $this->assertFalse(course_delete_section($course, 2, false)); $this->assertTrue(course_delete_section($course, 2, true)); $this->assertFalse($DB->record_exists('course_modules', array('id' => $assign21->cmid))); $this->assertFalse($DB->record_exists('course_modules', array('id' => $assign22->cmid))); $this->assertEquals(3, course_get_format($course)->get_course()->numsections); $this->assertEquals(array(0 => array($assign0->cmid), 1 => array($assign1->cmid), 2 => array($assign3->cmid), 3 => array($assign5->cmid)), get_fast_modinfo($course)->sections); // Make last section orphaned. update_course((object) array('id' => $course->id, 'numsections' => 2)); $this->assertEquals(2, course_get_format($course)->get_course()->numsections); // Remove orphaned section. $this->assertTrue(course_delete_section($course, 3, true)); $this->assertEquals(2, course_get_format($course)->get_course()->numsections); // Remove marked section. course_set_marker($course->id, 1); $this->assertTrue(course_get_format($course)->is_section_current(1)); $this->assertTrue(course_delete_section($course, 1, true)); $this->assertFalse(course_get_format($course)->is_section_current(1)); }
public function test_move_section_marker() { global $DB; $this->resetAfterTest(true); $this->getDataGenerator()->create_course(array('numsections' => 5), array('createsections' => true)); $course = $this->getDataGenerator()->create_course(array('numsections' => 10), array('createsections' => true)); // Set course marker to the section we are going to move.. course_set_marker($course->id, 2); // Verify that the course marker is set correctly. $course = $DB->get_record('course', array('id' => $course->id)); $this->assertEquals(2, $course->marker); // Test move the marked section down.. move_section_to($course, 2, 4); // Verify that the coruse marker has been moved along with the section.. $course = $DB->get_record('course', array('id' => $course->id)); $this->assertEquals(4, $course->marker); // Test move the marked section up.. move_section_to($course, 4, 3); // Verify that the course marker has been moved along with the section.. $course = $DB->get_record('course', array('id' => $course->id)); $this->assertEquals(3, $course->marker); // Test moving a non-marked section above the marked section.. move_section_to($course, 4, 2); // Verify that the course marker has been moved down to accomodate.. $course = $DB->get_record('course', array('id' => $course->id)); $this->assertEquals(4, $course->marker); // Test moving a non-marked section below the marked section.. move_section_to($course, 3, 6); // Verify that the course marker has been up to accomodate.. $course = $DB->get_record('course', array('id' => $course->id)); $this->assertEquals(3, $course->marker); }
/** * Moves a section up or down by 1. CANNOT BE USED DIRECTLY BY AJAX! * * @param object $course course object * @param int $section Section number (not id!!!) * @param int $move (-1 or 1) * @return boolean true if section moved successfully */ function move_section($course, $section, $move) { /// Moves a whole course section up and down within the course global $USER, $DB; if (!$move) { return true; } $sectiondest = $section + $move; if ($sectiondest > $course->numsections or $sectiondest < 1) { return false; } if (!($sectionrecord = $DB->get_record("course_sections", array("course" => $course->id, "section" => $section)))) { return false; } if (!($sectiondestrecord = $DB->get_record("course_sections", array("course" => $course->id, "section" => $sectiondest)))) { return false; } $DB->set_field("course_sections", "section", $sectiondest, array("id" => $sectionrecord->id)); $DB->set_field("course_sections", "section", $section, array("id" => $sectiondestrecord->id)); // Update highlighting if the move affects highlighted section if ($course->marker == $section) { course_set_marker($course->id, $sectiondest); } elseif ($course->marker == $sectiondest) { course_set_marker($course->id, $section); } // if the focus is on the section that is being moved, then move the focus along if (course_get_display($course->id) == $section) { course_set_display($course->id, $sectiondest); } // Check for duplicates and fix order if needed. // There is a very rare case that some sections in the same course have the same section id. $sections = $DB->get_records('course_sections', array('course' => $course->id), 'section ASC'); $n = 0; foreach ($sections as $section) { if ($section->section != $n) { $DB->set_field('course_sections', 'section', $n, array('id' => $section->id)); } $n++; } return true; }
/** * fix_course_marker */ function fix_course_marker() { global $COURSE; // get default marker value $marker = empty($COURSE->marker) ? 0 : $COURSE->marker; // get marker value from form $marker = optional_param('marker', $marker, PARAM_INT); // update if necessary if ($marker == $COURSE->marker) { // do nothing } else { if (has_capability('moodle/course:setcurrentsection', $this->page->context)) { $COURSE->marker = $marker; course_set_marker($COURSE->id, $marker); } } }
/** * @param string $shortname * @param int $sectionnumber * @param boolean $highlight * @throws \required_capability_exception * @return array */ public function highlight_section($shortname, $sectionnumber, $highlight) { global $OUTPUT; $course = $this->coursebyshortname($shortname); $context = \context_course::instance($course->id); require_capability('moodle/course:setcurrentsection', $context); $setsectionnumber = empty($highlight) ? 0 : $sectionnumber; course_set_marker($course->id, $setsectionnumber); $course->marker = $setsectionnumber; $modinfo = get_fast_modinfo($course); if ($highlight) { $section = $modinfo->get_section_info(0); } else { $section = $modinfo->get_section_info($sectionnumber); } $actionmodel = new \theme_snap\renderables\course_action_section_highlight($course, $section); $toc = new \theme_snap\renderables\course_toc($course); return ['actionmodel' => $actionmodel->export_for_template($OUTPUT), 'toc' => $toc->export_for_template($OUTPUT)]; }