diff --git a/course/format/formatlegacy.php b/course/format/formatlegacy.php new file mode 100644 index 00000000000..6672c7d58bf --- /dev/null +++ b/course/format/formatlegacy.php @@ -0,0 +1,181 @@ +. + +/** + * Course format class to allow plugins developed for Moodle 2.3 to work in the new API + * + * @package core_course + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * Course format class to allow plugins developed for Moodle 2.3 to work in the new API + * + * @package core_course + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class format_legacy extends format_base { + + /** + * Returns true if this course format uses sections + * + * This function calls function callback_FORMATNAME_uses_sections() if it exists + * + * @return bool + */ + function uses_sections() { + global $CFG; + // Note that lib.php in course format folder is already included by now + $featurefunction = 'callback_'.$this->format.'_uses_sections'; + if (function_exists($featurefunction)) { + return $featurefunction(); + } + return false; + } + + /** + * Returns the display name of the given section that the course prefers. + * + * This function calls function callback_FORMATNAME_get_section_name() if it exists + * + * @param int|stdClass $section Section object from database or just field section.section + * @return string Display name that the course format prefers, e.g. "Topic 2" + */ + function get_section_name($section) { + // Use course formatter callback if it exists + $namingfunction = 'callback_'.$this->format.'_get_section_name'; + if (function_exists($namingfunction) && ($course = $this->get_course())) { + return $namingfunction($course, $this->get_section($section)); + } + + // else, default behavior: + return parent::get_section_name($section); + } + + /** + * The URL to use for the specified course (with section) + * + * This function calls function callback_FORMATNAME_get_section_url() if it exists + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if omitted the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + // Use course formatter callback if it exists + $featurefunction = 'callback_'.$this->format.'_get_section_url'; + if (function_exists($featurefunction) && ($course = $this->get_course())) { + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + if ($sectionnum) { + $url = $featurefunction($course, $sectionnum); + if ($url || !empty($options['navigation'])) { + return $url; + } + } + } + + // else, default behavior: + return parent::get_view_url($section, $options); + } + + /** + * Returns the information about the ajax support in the given source format + * + * This function calls function callback_FORMATNAME_ajax_support() if it exists + * + * The returned object's property (boolean)capable indicates that + * the course format supports Moodle course ajax features. + * The property (array)testedbrowsers can be used as a parameter for {@see ajaxenabled()}. + * + * @return stdClass + */ + function supports_ajax() { + // set up default values + $ajaxsupport = parent::supports_ajax(); + + // get the information from the course format library + $featurefunction = 'callback_'.$this->format.'_ajax_support'; + if (function_exists($featurefunction)) { + $formatsupport = $featurefunction(); + if (isset($formatsupport->capable)) { + $ajaxsupport->capable = $formatsupport->capable; + } + if (is_array($formatsupport->testedbrowsers)) { + $ajaxsupport->testedbrowsers = $formatsupport->testedbrowsers; + } + } + return $ajaxsupport; + } + + /** + * Loads all of the course sections into the navigation + * + * First this function calls callback_FORMATNAME_display_content() if it exists to check + * if the navigation should be extended at all + * + * Then it calls function callback_FORMATNAME_load_content() if it exist to actually extend + * navigation + * + * By default the parent method is called + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + * @return array Array of sections where each element also contains the element 'sectionnode' + * referring to the corresponding section node + */ + public function extend_course_navigation(&$navigation, navigation_node $node) { + // check if there are callbacks to extend course navigation + $displayfunc = 'callback_'.$this->format.'_display_content'; + if (function_exists($displayfunc) && !$displayfunc()) { + return array(); + } + $featurefunction = 'callback_'.$this->format.'_load_content'; + if (function_exists($featurefunction) && ($course = $this->get_course())) { + return $featurefunction($navigation, $course, $node); + } else { + return parent::extend_navigation($navigation, $node); + } + } + + /** + * Custom action after section has been moved in AJAX mode + * + * Used in course/rest.php + * + * This function calls function callback_FORMATNAME_ajax_section_move() if it exists + * + * @return array This will be passed in ajax respose + */ + function ajax_section_move() { + $featurefunction = 'callback_'.$this->format.'_ajax_section_move'; + if (function_exists($featurefunction) && ($course = $this->get_course())) { + return $featurefunction($course); + } else { + return parent::ajax_section_move(); + } + } +} \ No newline at end of file diff --git a/course/format/lib.php b/course/format/lib.php new file mode 100644 index 00000000000..a1349dcaf89 --- /dev/null +++ b/course/format/lib.php @@ -0,0 +1,426 @@ +. + +/** + * Base class for course format plugins + * + * @package core_course + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * Returns an instance of format class (extending format_base) for given course + * + * @param int|stdClass $courseorid either course id or + * an object that has the property 'format' and may contain property 'id' + * @return format_base + */ +function course_get_format($courseorid) { + return format_base::instance($courseorid); +} + +/** + * Base class for course formats + * + * Each course format must declare class + * class format_FORMATNAME extends format_base {} + * in file lib.php + * + * For each course just one instance of this class is created and it will always be returned by + * course_get_format($courseorid). Format may store it's specific course-dependent options in + * variables of this class. + * + * In rare cases instance of child class may be created just for format without course id + * i.e. to check if format supports AJAX. + * + * Also course formats may extend class section_info and overwrite + * format_base::build_section_cache() to return more information about sections. + * + * If you are upgrading from Moodle 2.3 start with copying the class format_legacy and renaming + * it to format_FORMATNAME, then move the code from your callback functions into + * appropriate functions of the class. + * + * @package core_course + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +abstract class format_base { + /** @var int Id of the course in this instance (maybe 0) */ + protected $courseid; + /** @var string format used for this course. Please note that it can be different from + * course.format field if course referes to non-existing of disabled format */ + protected $format; + /** @var stdClass data for course object, please use {@link format_base::get_course()} */ + protected $course = false; + /** @var array cached instances */ + private static $instances = array(); + + /** + * Creates a new instance of class + * + * Please use {@link course_get_format($courseorid)} to get an instance of the format class + * + * @param string $format + * @param int $courseid + * @return format_base + */ + protected function __construct($format, $courseid) { + $this->format = $format; + $this->courseid = $courseid; + } + + /** + * Validates course format and returns either itself or default format name + * + * @param string $format + * @return string + */ + protected static final function get_used_format($format) { + if ($format === 'site') { + return $format; + } + $plugins = get_plugin_list('format'); // TODO filter only enabled + if (isset($plugins[$format])) { + return $format; + } + // Else return default format + $defaultformat = reset($plugins); // TODO get default format from config + debugging('Format plugin format_'.$format.' is not found or is not enabled. Using default format_'.$defaultformat); + return $defaultformat; + } + + /** + * Get class name for the format + * + * If course format xxx does not declare class format_xxx, format_legacy will be returned. + * This function also includes lib.php file from corresponding format plugin + * + * @param string $format + * @return string + */ + protected static final function get_class_name($format) { + global $CFG; + static $classnames = array('site' => 'format_site'); + if (!isset($classnames[$format])) { + $plugins = get_plugin_list('format'); + $usedformat = self::get_used_format($format); + if (file_exists($plugins[$usedformat].'/lib.php')) { + require_once $plugins[$usedformat].'/lib.php'; + } + $classnames[$format] = 'format_'. $usedformat; + if (!class_exists($classnames[$format])) { + require_once $CFG->dirroot.'/course/format/formatlegacy.php'; + $classnames[$format] = 'format_legacy'; + } + } + return $classnames[$format]; + } + + /** + * Returns an instance of the class + * + * @todo use MUC for caching of instances, limit the number of cached instances + * + * @param int|stdClass $courseorid either course id or + * an object that has the property 'format' and may contain property 'id' + * @return format_base + */ + public static final function instance($courseorid) { + global $DB; + if (!is_object($courseorid)) { + $courseid = (int)$courseorid; + if ($courseid && isset(self::$instances[$courseid]) && count(self::$instances[$courseid]) == 1) { + $format = reset(array_keys(self::$instances[$courseid])); + } else { + $format = $DB->get_field('course', 'format', array('id' => $courseid), MUST_EXIST); + } + } else { + $format = $courseorid->format; + if (isset($courseorid->id)) { + $courseid = (int)$courseorid->id; + } else { + $courseid = 0; + } + } + // validate that format exists and enabled, use default otherwise + $format = self::get_used_format($format); + if (!isset(self::$instances[$courseid][$format])) { + $classname = self::get_class_name($format); + self::$instances[$courseid][$format] = new $classname($format, $courseid); + } + return self::$instances[$courseid][$format]; + } + + /** + * Resets cache for the course (or all caches) + * To be called from {@link rebuild_course_cache()} + * + * @param int $courseid + */ + public static final function reset_course_cache($courseid = 0) { + if ($courseid) { + if (isset(self::$instances[$courseid])) { + foreach (self::$instances[$courseid] as $format => $object) { + // in case somebody keeps the reference to course format object + self::$instances[$courseid][$format]->course = false; + } + unset(self::$instances[$courseid]); + } + } else { + self::$instances = array(); + } + } + + /** + * Returns the format name used by this course + * + * @return string + */ + public final function get_format() { + return $this->format; + } + + /** + * Returns id of the course (0 if course is not specified) + * + * @return int + */ + public final function get_courseid() { + return $this->courseid; + } + + /** + * Returns a record from course database table plus additional fields + * that course format defines + * + * @return stdClass + */ + public function get_course() { + global $DB; + if (!$this->courseid) { + return null; + } + if ($this->course === false) { + $this->course = $DB->get_record('course', array('id' => $this->courseid)); + } + return $this->course; + } + + /** + * Returns true if this course format uses sections + * + * This function may be called without specifying the course id + * i.e. in {@link course_format_uses_sections()} + * + * Developers, note that if course format does use sections there should be defined a language + * string with the name 'sectionname' defining what the section relates to in the format, i.e. + * $string['sectionname'] = 'Topic'; + * or + * $string['sectionname'] = 'Week'; + * + * @return bool + */ + public function uses_sections() { + return false; + } + + /** + * Returns a list of sections used in the course + * + * This is a shortcut to get_fast_modinfo()->get_section_info_all() + * @see get_fast_modinfo() + * @see course_modinfo::get_section_info_all() + * + * @return array of section_info objects + */ + public final function get_sections() { + if ($course = $this->get_course()) { + $modinfo = get_fast_modinfo($course); + return $modinfo->get_section_info_all(); + } + return array(); + } + + /** + * Returns information about section used in course + * + * @param int|stdClass $section either section number (field course_section.section) or row from course_section table + * @param int $strictness + * @return section_info + */ + public final function get_section($section, $strictness = IGNORE_MISSING) { + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + $sections = $this->get_sections(); + if (array_key_exists($sectionnum, $sections)) { + return $sections[$sectionnum]; + } + if ($strictness == MUST_EXIST) { + throw new moodle_exception('sectionnotexist'); + } + return null; + } + + /** + * Returns the display name of the given section that the course prefers. + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * @return Display name that the course format prefers, e.g. "Topic 2" + */ + public function get_section_name($section) { + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + return get_string('sectionname', 'format_'.$this->format) . ' ' . $sectionnum; + } + + /** + * Returns the information about the ajax support in the given source format + * + * The returned object's property (boolean)capable indicates that + * the course format supports Moodle course ajax features. + * The property (array)testedbrowsers can be used as a parameter for {@see ajaxenabled()}. + * + * @return stdClass + */ + public function supports_ajax() { + // no support by default + $ajaxsupport = new stdClass(); + $ajaxsupport->capable = false; + $ajaxsupport->testedbrowsers = array(); + return $ajaxsupport; + } + + /** + * Custom action after section has been moved in AJAX mode + * + * Used in course/rest.php + * + * @return array This will be passed in ajax respose + */ + public function ajax_section_move() { + return null; + } + + /** + * The URL to use for the specified course (with section) + * + * Please note that course view page /course/view.php?id=COURSEID is hardcoded in many + * places in core and contributed modules. If course format wants to change the location + * of the view script, it is not enough to change just this function. Do not forget + * to add proper redirection. + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if null the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + $course = $this->get_course(); + $url = new moodle_url('/course/view.php', array('id' => $course->id)); + + $sr = null; + if (array_key_exists('sr', $options)) { + $sr = $options['sr']; + } + if (is_object($section)) { + $sectionno = $section->section; + } else { + $sectionno = $section; + } + if ($sectionno !== null) { + if ($sr !== null) { + if ($sr) { + $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; + $sectionno = $sr; + } else { + $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; + } + } else { + $usercoursedisplay = $course->coursedisplay; + } + if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { + $url->param('section', $sectionno); + } else { + if (!empty($options['navigation'])) { + return null; + } + $url->set_anchor('section-'.$sectionno); + } + } + return $url; + } + + /** + * Loads all of the course sections into the navigation + * + * By default the method {@link global_navigation::load_generic_course_sections()} is called + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + * @return array Array of sections where each element also contains the element 'sectionnode' + * referring to the corresponding section node + */ + public function extend_course_navigation(&$navigation, navigation_node $node) { + if ($course = $this->get_course()) { + return $navigation->load_generic_course_sections($course, $node); + } + return array(); + } +} + +/** + * Pseudo course format used for the site main page + * + * @package core_course + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class format_site extends format_base { + + /** + * Returns the display name of the given section that the course prefers. + * + * @param int|stdClass $section Section object from database or just field section.section + * @return Display name that the course format prefers, e.g. "Topic 2" + */ + function get_section_name($section) { + return get_string('site'); + } + + /** + * For this fake course referring to the whole site, the site homepage is always returned + * regardless of arguments + * + * @param int|stdClass $section + * @param array $options + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + return new moodle_url('/'); + } +} + diff --git a/course/format/upgrade.txt b/course/format/upgrade.txt index d4a6d7f4e7f..6105465ff1b 100644 --- a/course/format/upgrade.txt +++ b/course/format/upgrade.txt @@ -4,6 +4,10 @@ Overview of this plugin type at http://docs.moodle.org/dev/Course_formats === 2.4 === +Course format API has been changed significantly. Instead of implementing callbacks course formats +may overwrite the class format_base. See format_legacy class for a template for upgrading course +format. + * Function settings_navigation::add_course_editing_links() is completely removed, course format functions callback_XXXX_request_key() are no longer used (where XXXX is the course format name) diff --git a/course/lib.php b/course/lib.php index d3395566767..a19e2843723 100644 --- a/course/lib.php +++ b/course/lib.php @@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die; require_once($CFG->libdir.'/completionlib.php'); require_once($CFG->libdir.'/filelib.php'); require_once($CFG->dirroot.'/course/dnduploadlib.php'); +require_once($CFG->dirroot.'/course/format/lib.php'); define('COURSE_MAX_LOGS_PER_PAGE', 1000); // records define('COURSE_MAX_RECENT_PERIOD', 172800); // Two days, in seconds @@ -3654,68 +3655,29 @@ function move_category($category, $newparentcat) { } /** - * Returns the display name of the given section that the course prefers. + * Returns the display name of the given section that the course prefers * - * This function utilizes a callback that can be implemented within the course - * formats lib.php file to customize the display name that is used to reference - * the section. + * Implementation of this function is provided by course format + * @see format_base::get_section_name() * - * By default (if callback is not defined) the method - * {@see get_numeric_section_name} is called instead. - * - * @param stdClass $course The course to get the section name for - * @param stdClass $section Section object from database - * @return Display name that the course format prefers, e.g. "Week 2" - * - * @see get_generic_section_name + * @param int|stdClass $courseorid The course to get the section name for (object or just course id) + * @param int|stdClass $section Section object from database or just field course_sections.section + * @return string Display name that the course format prefers, e.g. "Week 2" */ -function get_section_name(stdClass $course, stdClass $section) { - global $CFG; - - /// Inelegant hack for bug 3408 - if ($course->format == 'site') { - return get_string('site'); - } - - // Use course formatter callback if it exists - $namingfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; - $namingfunction = 'callback_'.$course->format.'_get_section_name'; - if (!function_exists($namingfunction) && file_exists($namingfile)) { - require_once $namingfile; - } - if (function_exists($namingfunction)) { - return $namingfunction($course, $section); - } - - // else, default behavior: - return get_generic_section_name($course->format, $section); +function get_section_name($courseorid, $section) { + return course_get_format($courseorid)->get_section_name($section); } /** - * Gets the generic section name for a courses section. + * Tells if current course format uses sections * * @param string $format Course format ID e.g. 'weeks' $course->format - * @param stdClass $section Section object from database - * @return Display name that the course format prefers, e.g. "Week 2" + * @return bool */ -function get_generic_section_name($format, stdClass $section) { - return get_string('sectionname', "format_$format") . ' ' . $section->section; -} - - function course_format_uses_sections($format) { - global $CFG; - - $featurefile = $CFG->dirroot.'/course/format/'.$format.'/lib.php'; - $featurefunction = 'callback_'.$format.'_uses_sections'; - if (!function_exists($featurefunction) && file_exists($featurefile)) { - require_once $featurefile; - } - if (function_exists($featurefunction)) { - return $featurefunction(); - } - - return false; + $course = new stdClass(); + $course->format = $format; + return course_get_format($course)->uses_sections(); } /** @@ -3729,30 +3691,9 @@ function course_format_uses_sections($format) { * @return stdClass */ function course_format_ajax_support($format) { - global $CFG; - - // set up default values - $ajaxsupport = new stdClass(); - $ajaxsupport->capable = false; - $ajaxsupport->testedbrowsers = array(); - - // get the information from the course format library - $featurefile = $CFG->dirroot.'/course/format/'.$format.'/lib.php'; - $featurefunction = 'callback_'.$format.'_ajax_support'; - if (!function_exists($featurefunction) && file_exists($featurefile)) { - require_once $featurefile; - } - if (function_exists($featurefunction)) { - $formatsupport = $featurefunction(); - if (isset($formatsupport->capable)) { - $ajaxsupport->capable = $formatsupport->capable; - } - if (is_array($formatsupport->testedbrowsers)) { - $ajaxsupport->testedbrowsers = $formatsupport->testedbrowsers; - } - } - - return $ajaxsupport; + $course = new stdClass(); + $course->format = $format; + return course_get_format($course)->supports_ajax(); } /** @@ -4598,44 +4539,14 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules = /** * The URL to use for the specified course (with section) * - * @param stdClass $course The course to get the section name for - * @param int $sectionno The section number to return a link to + * @param int|stdClass $courseorid The course to get the section name for (either object or just course id) + * @param int|stdClass $section Section object from database or just field course_sections.section * if omitted the course view page is returned * @param array $options options for view URL. At the moment core uses: * 'navigation' (bool) if true and section has no separate page, the function returns null * 'sr' (int) used by multipage formats to specify to which section to return * @return moodle_url The url of course */ -function course_get_url($course, $sectionno = null, $options = array()) { - if ($course->id == SITEID) { - return new moodle_url('/'); - } - $url = new moodle_url('/course/view.php', array('id' => $course->id)); - - $sr = null; - if (array_key_exists('sr', $options)) { - $sr = $options['sr']; - } - if ($sectionno !== null) { - if ($sr !== null) { - if ($sr) { - $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; - $sectionno = $sr; - } else { - $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; - } - } else { - $usercoursedisplay = $course->coursedisplay; - } - if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { - $url->param('section', $sectionno); - } else { - if (!empty($options['navigation'])) { - return null; - } - $url->set_anchor('section-'.$sectionno); - } - } - - return $url; +function course_get_url($courseorid, $section = null, $options = array()) { + return course_get_format($courseorid)->get_view_url($section, $options); } diff --git a/course/rest.php b/course/rest.php index 54d473b43e7..35f685a9399 100644 --- a/course/rest.php +++ b/course/rest.php @@ -91,13 +91,9 @@ switch($requestmethod) { require_capability('moodle/course:movesections', $coursecontext); move_section_to($course, $id, $value); // See if format wants to do something about it - $libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; - $functionname = 'callback_'.$course->format.'_ajax_section_move'; - if (!function_exists($functionname) && file_exists($libfile)) { - require_once $libfile; - } - if (function_exists($functionname)) { - echo json_encode($functionname($course)); + $response = course_get_format($course)->ajax_section_move(); + if ($response !== null) { + echo json_encode($response); } break; } diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 43824bd71ae..bc1d24db894 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -2907,3 +2907,20 @@ function textlib_get_instance() { return new textlib(); } +/** + * Gets the generic section name for a courses section + * + * The global function is deprecated. Each course format can define their own generic section name + * + * @deprecated since 2.4 + * @see get_section_name() + * @see format_base::get_section_name() + * + * @param string $format Course format ID e.g. 'weeks' $course->format + * @param stdClass $section Section object from database + * @return Display name that the course format prefers, e.g. "Week 2" + */ +function get_generic_section_name($format, stdClass $section) { + debugging('get_generic_section_name() is deprecated. Please use appropriate functionality from class format_base', DEBUG_DEVELOPER); + return get_string('sectionname', "format_$format") . ' ' . $section->section; +} diff --git a/lib/modinfolib.php b/lib/modinfolib.php index 6c8997c1499..7f176239968 100644 --- a/lib/modinfolib.php +++ b/lib/modinfolib.php @@ -1235,6 +1235,11 @@ function rebuild_course_cache($courseid=0, $clearonly=false) { // Destroy navigation caches navigation_cache::destroy_volatile_caches(); + if (class_exists('format_base')) { + // if file containing class is not loaded, there is no cache there anyway + format_base::reset_course_cache($courseid); + } + if ($clearonly) { if (empty($courseid)) { $DB->set_field('course', 'modinfo', null); diff --git a/lib/navigationlib.php b/lib/navigationlib.php index d781b6f9626..9b35114227a 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -1252,10 +1252,8 @@ class global_navigation extends navigation_node { } // Add the essentials such as reports etc... $this->add_course_essentials($coursenode, $course); - if ($this->format_display_course_content($course->format)) { - // Load the course sections - $sections = $this->load_course_sections($course, $coursenode); - } + // Extend course navigation with it's sections/activities + $this->load_course_sections($course, $coursenode); if (!$coursenode->contains_active_node() && !$coursenode->search_for_active_node()) { $coursenode->make_active(); } @@ -1384,7 +1382,7 @@ class global_navigation extends navigation_node { break; } $this->add_course_essentials($coursenode, $course); - $sections = $this->load_course_sections($course, $coursenode); + $this->load_course_sections($course, $coursenode); break; } @@ -1486,32 +1484,6 @@ class global_navigation extends navigation_node { return $this->showcategories; } - /** - * Checks the course format to see whether it wants the navigation to load - * additional information for the course. - * - * This function utilises a callback that can exist within the course format lib.php file - * The callback should be a function called: - * callback_{formatname}_display_content() - * It doesn't get any arguments and should return true if additional content is - * desired. If the callback doesn't exist we assume additional content is wanted. - * - * @param string $format The course format - * @return bool - */ - protected function format_display_course_content($format) { - global $CFG; - $formatlib = $CFG->dirroot.'/course/format/'.$format.'/lib.php'; - if (file_exists($formatlib)) { - require_once($formatlib); - $displayfunc = 'callback_'.$format.'_display_content'; - if (function_exists($displayfunc) && !$displayfunc()) { - return $displayfunc(); - } - } - return true; - } - /** * Loads the courses in Moodle into the navigation. * @@ -1898,20 +1870,8 @@ class global_navigation extends navigation_node { */ protected function load_course_sections(stdClass $course, navigation_node $coursenode) { global $CFG; - $structurefile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; - $structurefunc = 'callback_'.$course->format.'_load_content'; - if (function_exists($structurefunc)) { - return $structurefunc($this, $course, $coursenode); - } else if (file_exists($structurefile)) { - require_once $structurefile; - if (function_exists($structurefunc)) { - return $structurefunc($this, $course, $coursenode); - } else { - return $this->load_generic_course_sections($course, $coursenode); - } - } else { - return $this->load_generic_course_sections($course, $coursenode); - } + require_once($CFG->dirroot.'/course/lib.php'); + return course_get_format($course)->extend_course_navigation($this, $coursenode); } /** @@ -1980,26 +1940,14 @@ class global_navigation extends navigation_node { * * @param stdClass $course * @param navigation_node $coursenode - * @param string $courseformat The course format * @return array An array of course section nodes */ - public function load_generic_course_sections(stdClass $course, navigation_node $coursenode, $courseformat='unknown') { + public function load_generic_course_sections(stdClass $course, navigation_node $coursenode) { global $CFG, $DB, $USER, $SITE; require_once($CFG->dirroot.'/course/lib.php'); list($sections, $activities) = $this->generate_sections_and_activities($course); - $namingfunction = 'callback_'.$courseformat.'_get_section_name'; - $namingfunctionexists = (function_exists($namingfunction)); - - $urlfunction = 'callback_'.$courseformat.'_get_section_url'; - if (function_exists($urlfunction)) { - // This code path is deprecated but we decided not to warn developers as - // major changes are likely to follow in 2.4. See MDL-32504. - } else { - $urlfunction = null; - } - $key = 0; if (defined('AJAX_SCRIPT') && AJAX_SCRIPT == '0' && $this->page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { $key = optional_param('section', $key, PARAM_INT); @@ -2016,19 +1964,9 @@ class global_navigation extends navigation_node { continue; } - if ($namingfunctionexists) { - $sectionname = $namingfunction($course, $section, $sections); - } else { - $sectionname = get_string('section').' '.$section->section; - } + $sectionname = get_section_name($course, $section); + $url = course_get_url($course, $section->section, array('navigation' => true)); - $url = null; - if ($urlfunction) { - // pre 2.3 style format url - $url = $urlfunction($course->id, $section->section); - }else{ - $url = course_get_url($course, $section->section, array('navigation' => true)); - } $sectionnode = $coursenode->add($sectionname, $url, navigation_node::TYPE_SECTION, null, $section->id); $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH; $sectionnode->hidden = (!$section->visible || !$section->available); @@ -2863,9 +2801,7 @@ class global_navigation_for_ajax extends global_navigation { $this->page->set_context(context_course::instance($course->id)); $coursenode = $this->add_course($course); $this->add_course_essentials($coursenode, $course); - if ($this->format_display_course_content($course->format)) { - $this->load_course_sections($course, $coursenode); - } + $this->load_course_sections($course, $coursenode); break; case self::TYPE_SECTION : $sql = 'SELECT c.*, cs.section AS sectionnumber diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 10c3bb14d18..d7d8e6cf78a 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -7,6 +7,11 @@ information provided here is intended especially for developers. and page_generic_activity. * use $CFG->googlemapkey3 instead of removed $CFG->googlemapkey and migrate to Google Maps API V3 * Function settings_navigation::add_course_editing_links() is completely removed +* function get_generic_section_name() is deprecated +* function global_navigation::format_display_course_content() is removed completely (the + functionality is moved to course format class) +* in the function global_navigation::load_generic_course_sections() the argument $courseformat is + removed YUI changes: * moodle-enrol-notification has been renamed to moodle-core-notification