/** * Create a new subpage instance * * @param array|stdClass $record The record to insert to subpage table * @param mod_subpage $subpage Subpage object * @param array $options Optional parameters * @return mod_subpage Subpage object created */ public function create_instance($record = null, array $options = null) { global $DB, $CFG; $record = (object) (array) $record; if (!isset($record->enablesharing)) { $record->enablesharing = 0; } $result = parent::create_instance($record, (array) $options); if (!empty($record->addsection)) { require_once $CFG->dirroot . '/mod/subpage/locallib.php'; $subobj = mod_subpage::get_from_cmid($result->cmid); $subobj->add_section(); } return $result; }
/** * Given an ID of an instance of this module, * this function will permanently delete the instance * and any data that depends on it. * * @global object * @param int $id * @return bool */ function subpage_delete_instance($id) { global $DB, $PAGE, $CFG; if (!($subpage = $DB->get_record("subpage", array("id" => $id)))) { return false; } require_once $CFG->dirroot . '/mod/subpage/locallib.php'; $transaction = $DB->start_delegated_transaction(); // if deleting a subpage activity from course/mod.php page (not delete the whole course) if ($PAGE->pagetype == 'course-mod') { $subpagecmid = required_param('delete', PARAM_INT); // Check if all the sections in this subpage is empty $subpageinstance = mod_subpage::get_from_cmid($subpagecmid); $subpagesections = $DB->get_records('subpage_sections', array("subpageid" => $subpage->id), '', 'sectionid'); foreach ($subpagesections as $sections) { if (!$subpageinstance->is_section_empty($sections->sectionid)) { // Section is not empty $url = new moodle_url('/mod/subpage/view.php', array('id' => $subpagecmid)); print_error('error_deletingsubpage', 'mod_subpage', $url); } } // all sections are empty, delete the empty sections foreach ($subpagesections as $sections) { $subpageinstance->delete_section($sections->sectionid); } } // Delete main table and sections $DB->delete_records("subpage", array("id" => $subpage->id)); $DB->delete_records("subpage_sections", array("subpageid" => $subpage->id)); // If there are any shared subpages that reference this, rebuild those // courses so that they reflect the deletion if ($DB->get_field('modules', 'id', array('name' => 'sharedsubpage'))) { $references = $DB->get_records('sharedsubpage', array('subpageid' => $subpage->id), 'id,course'); foreach ($references as $sharedsubpage) { rebuild_course_cache($sharedsubpage->course, true); } } $transaction->allow_commit(); return true; }
$addsection = optional_param('addsection', 0, PARAM_INT); $recache = optional_param('recache', 0, PARAM_INT); $cancelcopy = optional_param('cancelcopy', 0, PARAM_BOOL); if (empty($cmid)) { print_error('unspecifysubpageid', 'subpage'); } if (!empty($cancelcopy) && confirm_sesskey()) { unset($USER->activitycopy); unset($USER->activitycopycourse); unset($USER->activitycopyname); redirect("view.php?id={$cmid}"); } // This must be done first because some horrible combination of junk means that // page might be initialised before we expect. $PAGE->set_pagelayout('incourse'); $subpage = mod_subpage::get_from_cmid($cmid); $course = $subpage->get_course(); // Defined here to avoid notices on errors etc. $thisurl = new moodle_url('/mod/subpage/view.php', array('id' => $cmid)); $PAGE->set_url($thisurl); $PAGE->set_cm($subpage->get_course_module()); $modcontext = context_module::instance($cmid); require_login($course, true, $subpage->get_course_module()); require_capability('mod/subpage:view', $modcontext); $event = \mod_subpage\event\course_module_viewed::create(array('objectid' => $subpage->get_course_module()->instance, 'context' => $modcontext)); $event->add_record_snapshot('course', $course); $event->trigger(); if (!empty($recache) && confirm_sesskey()) { $context = context_course::instance($subpage->get_course()->id); require_capability('moodle/course:manageactivities', $context); rebuild_course_cache($course->id, true);
/** * Obtains last subpage section id for a given subpage. * @param integer $subpagecmid * @return last section id for a given subpage */ public function get_last_subpage_section_id($subpagecmid) { global $DB, $CFG; $sql = "SELECT sectionid\n FROM {subpage_sections}\n WHERE subpageid = (select instance from {course_modules} where id = ?)\n ORDER BY pageorder DESC"; $params = array($subpagecmid); $records = $DB->get_records_sql($sql, $params, 0, 1); if (count($records) == 0) { // When there are no sections, add one require_once $CFG->dirroot . '/mod/subpage/locallib.php'; $subpage = mod_subpage::get_from_cmid($subpagecmid); $subpage->add_section(); // Redo the query $records = $DB->get_records_sql($sql, $params, 0, 1); if (count($records) == 0) { throw new coding_exception("No section defined in subpage {$subpagecmid}"); } } return reset($records)->sectionid; }
/** * Display intro section. * @param mod_subpage $subpage Module object * @return string Intro HTML or '' if none */ public function render_intro(mod_subpage $subpage) { // Don't output anything if no text, so we don't get styling around // something blank if (!$subpage->has_intro()) { return ''; } // Make fake activity object in required format, and use to format // intro for module with standard function (which handles images etc.) $activity = (object) array('intro' => $subpage->get_intro(), 'introformat' => $subpage->get_intro_format()); $intro = format_module_intro('subpage', $activity, $subpage->get_course_module()->id); // Box styling appears to be consistent with some other modules $intro = html_writer::tag('div', $intro, array('class' => 'generalbox box', 'id' => 'intro')); return $intro; }
if (substr($key, 0, 3) === 'mod' && $data == 1) { $cmids[] = substr($key, 3); } } if (empty($cmids)) { echo $OUTPUT->header(); // Course wrapper start. echo html_writer::start_tag('div', array('class' => 'course-content')); echo $OUTPUT->notification(get_string('nomodulesselected', 'mod_subpage')); echo $OUTPUT->continue_button("{$CFG->wwwroot}/mod/subpage/view.php?id={$cmid}"); echo html_writer::end_tag('div'); echo $OUTPUT->footer(); exit; } else { // destination is either null or a subpage $dest = $info[0] !== 'course' ? mod_subpage::get_from_cmid($info[0]) : null; if ($createnew && $dest) { $newsection = $dest->add_section(); $id = $newsection['sectionid']; } else { $id = $info[1]; } // ensure that the destination section does exists if (!($section = $DB->get_record('course_sections', array('id' => (int) $id)))) { print_error('sectionnotcreatedorexisting', 'mod_subpage', "{$CFG->wwwroot}/mod/subpage/view.php?id={$cmid}"); } foreach ($cmids as $id) { if (!($cm = get_coursemodule_from_id('', $id))) { print_error('modulenotfound', 'mod_subpage', "{$CFG->wwwroot}/mod/subpage/view.php?id={$cmid}"); } // no reason to move if in the same section
/** * Modifies XML files from a backup before doing the restore. * @param string $path Path to backup root * @param int $courseid Target course id * @param array $sectionids ids for each section in subpage (given new number) * @param int $spsectionid Section id for this subpage (set to 0) * @param int $spid cm id for this subpage (used to hide it) */ private function update_backup($path, $courseid, $sectionids, $spsectionid, $spid = null) { // List all files in backup so we can search through it later. $allfiles = self::list_files_recursive($path); // Create array of original id and new number. $sections = array($spsectionid => 0); $minnumber = null; foreach ($sectionids as $sectionid) { $minnumber = \mod_subpage::add_course_section($courseid, $minnumber); $sections[$sectionid] = $minnumber; } // Update section number (title element???) with empty value on target course. foreach (self::get_matching_files($path, $allfiles, '(moodle_backup.xml)') as $file) { $dom = new \DOMDocument(); $dom->load($file); $xpath = new \DOMXpath($dom); foreach ($xpath->query('/contents/sections/section/sectionid') as $node) { if (in_array($node->nodeValue, $sectionids)) { $titlenode = $node->parentNode->getElemetsByTagName('title')[0]; $titlenode->nodeValue = $sections[$node->nodeValue]; } } $dom->save($file); } // Update section number in each section xml. foreach ($sections as $origid => $newnum) { foreach (self::get_matching_files($path, $allfiles, "(.*/section_{$origid}/section\\.xml)") as $file) { $dom = new \DOMDocument(); $dom->load($file); $xpath = new \DOMXpath($dom); foreach ($xpath->query('/section/number') as $node) { $node->nodeValue = $newnum; } $dom->save($file); } } // Hide subpage if id sent. if ($spid) { foreach (self::get_matching_files($path, $allfiles, "(.*/subpage_{$spid}/module\\.xml)") as $file) { $dom = new \DOMDocument(); $dom->load($file); $xpath = new \DOMXpath($dom); foreach ($xpath->query('/module/visible') as $node) { $node->nodeValue = 0; } $dom->save($file); } } // Ensure we don't copy groups and groupings. file_put_contents($path . '/groups.xml', '<groups></groups>'); // If there are no quizzes included then don't copy the question bank. if (!self::get_matching_files($path, $allfiles, "activities/quiz_[0-9]+/module\\.xml")) { file_put_contents($path . '/questions.xml', '<question_categories></question_categories>'); } }
/** * Return an array of modules that can be moved in this situation * * The Array is keyed first with sections (subpage or main course) * and then the modules within each section by cmid. * * @param mod_subpage $subpage Current subpage * @param array $allsubpages Array of other subpage objects * @param array $coursesections Array of course sections * @param course_modinfo $modinfo Modinfo object * @param string $move Whether to move 'to' or 'from' the current subpage * @return array An array of items organised by section */ public static function moveable_modules(mod_subpage $subpage, array $allsubpages, $coursesections, course_modinfo $modinfo, $move) { $modinfo = get_fast_modinfo($subpage->get_course()->id); $allmods = $modinfo->get_cms(); $modnames = get_module_types_names(); $modnamesplural = get_module_types_names(true); $mods = array(); if ($move === 'to') { $parentcmids = array(); // Get the subpage cm that owns each section. $subpagesectioncm = array(); foreach ($modinfo->get_instances_of('subpage') as $subpageid => $cm) { // Get sectionsids array stored in the customdata. $cmdata = $cm->customdata; if ($cmdata) { foreach ($cmdata->sectionids as $sectionid) { $subpagesectioncm[$sectionid] = $cm; } } } // Loop through ancestor subpages. $cm = $modinfo->get_cm($subpage->get_course_module()->id); while (true) { if (array_key_exists($cm->section, $subpagesectioncm)) { $cm = $subpagesectioncm[$cm->section]; // In case of a subpage within itself, prevent endless loop. if (array_key_exists($cm->id, $parentcmids)) { break; } $parentcmids[$cm->id] = true; } else { break; } } } $subsections = array(); if (!empty($allsubpages) && $move === 'to') { foreach ($allsubpages as $sub) { $subsections += $sub->get_sections(); } $sections = $coursesections; } else { $subsections = $subpage->get_sections(); $sections = $subsections; } if ($sections) { foreach ($sections as $section) { if (!empty($section->sequence)) { if ($move === 'to' && array_key_exists($section->id, $subsections)) { continue; } $sectionalt = isset($section->pageorder) ? $section->pageorder : $section->section; if ($move === 'to') { // Include the required course/format library. global $CFG; require_once "{$CFG->dirroot}/course/format/" . $subpage->get_course()->format . "/lib.php"; $callbackfunction = 'callback_' . $subpage->get_course()->format . '_get_section_name'; if (function_exists($callbackfunction)) { $name = $callbackfunction($subpage->get_course(), $section); } else { $name = $section->name ? $section->name : get_string('section') . ' ' . $sectionalt; } } else { $name = $section->name ? $section->name : get_string('section') . ' ' . $sectionalt; } $sectionmods = explode(',', $section->sequence); foreach ($sectionmods as $modnumber) { if (empty($allmods[$modnumber]) || $modnumber === $subpage->get_course_module()->id) { continue; } if ($move === 'to') { // Prevent moving a parent subpage to its child. if (!empty($parentcmids[$modnumber])) { continue; } } $instancename = format_string($modinfo->cms[$modnumber]->name, true, $subpage->get_course()->id); $icon = $modinfo->get_cm($modnumber)->get_icon_url(); $mod = $allmods[$modnumber]; $mods[$section->section]['section'] = $name; $mods[$section->section]['pageorder'] = $sectionalt; $mods[$section->section]['mods'][$modnumber] = "<span><img src='{$icon}' /> " . $instancename . "</span>"; } } } } return $mods; }
public function test_subpage_get_course_subpages() { // setup a course and some modules $course = $this->get_new_course(); $coursesection = $this->get_new_course_section($course->id); $subpage1 = $this->get_new_subpage($course->id, "subpage1"); $cm1 = $this->get_new_course_module($course->id, $subpage1->id, $coursesection->id); $subpage2 = $this->get_new_subpage($course->id, "subpage2"); $cm2 = $this->get_new_course_module($course->id, $subpage2->id, $coursesection->id); $subpage3 = $this->get_new_subpage($course->id, "subpage3"); $cm3 = $this->get_new_course_module($course->id, $subpage3->id, $coursesection->id); $allsubpages = mod_subpage::get_course_subpages($course); $this->assertIsA($allsubpages, 'array'); $this->assertIsA($allsubpages[1], 'mod_subpage'); $this->assertEqual($allsubpages[1]->get_name(), 'subpage1'); $this->assertEqual($allsubpages[2]->get_name(), 'subpage2'); $this->assertEqual($allsubpages[3]->get_name(), 'subpage3'); $subpage = $allsubpages[1]; $section = $subpage->add_section('section1', 'section1'); $sectionid = $section['sectionid']; }