If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Course formats 2

From MoodleDocs
Revision as of 13:22, 14 July 2021 by David Mudrak (talk | contribs) (Text replacement - "class="nicetable"" to "class="wikitable"")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Course formats refactoring
Tracker issue MDL-35218
Assignee Marina Glancy

Moodle 2.4

We will refactor the course formats to support a proper object-oriented design and flexibility

Database changes

  • change course.format from varchar(10) to varchar(21)
  • add table course_format_options that will store format-specific options for the whole course and for specific secions (fields: id, courseid, format, sectionid[optional], name, value)
  • remove existing fields in table course: numsections, hiddensections, coursedisplay

Object model

Course formats must be classes inheriting base class format_base instead of the current collection of callbacks. (Although some callbacks will be converted to methods)

Method course_get_format($course) will return an instance of this class for the particular course. May be called with specific format but with empty course id (i.e. when course is being created)

Class format_base

method description
get_default_blocks() replaces config.php with $format[‘defaultblocks’]
course_format_options() definitions of the additional options that this course format uses for course
section_format_options() definitions of the additional options that this course format uses for section
edit_form_validation() performs additional validation for edit course form
page_set_course() is called from moodle_page::set_course() allowing course formats to run custom code at that point
page_set_cm() is called from moodle_page::set_cm()
output_course_header() displays the course-specific header. It will be included in all core themes, custom themes need to add support for it. Inside it should call function from renderer
output_course_footer() displays the course-specific footer
output_course_content_header() displays the course-specific header to be displayed in main content section (i.e. prev-next module navigation)
output_course_content_footer() displays the course-specific footer to be displayed in main content section (i.e. prev-next module navigation)
editsection_form() returns an instance of editsection_form (the format can overwrite this form)
is_section_current() replaces format_section_renderer_base::is_section_current()
get_section_name() is called from global function get_section_name()
uses_sections() is called from global function course_format_uses_sections()
supports_ajax() is called from global function course_format_ajax_support()
extend_course_navigation() replaces callback_FORMAT_load_content()
get_view_url() is called from course_get_url() and replaces callback_FORMAT_get_section_url()

Backward compartibility

Define class format_legacy extends format_base that will call the existing callbacks and get blocks from config.php if format class is not defined (2.0-2.3 backward compartibility). Function course_get_format() will return instance of this class if the course format does not define its own class

Course sections hierarchy

Add support for nested course sections:

  • avoid loops,
  • store visibleold;
  • Process moving, deleting sections;
  • Make sure the hierarchy appears in navigation menu and breadcrumb;
  • Make sure changing of availability rules for both parent and child sections works correctly together

Core formats will NOT support hierarchy, we just want to make sure that non-plugin code can deal with it

Course add/edit form

  • When course is created/edited, the options specific for the format are displayed in separate form section and it dynamically changes when format is changed (with support of non-js mode). Each course format defines which display options it needs. For the standard weeks/topics formatd they are [numsections, hiddensections, coursedisplay], for scrom and social there are no options
  • Make Course format selector on create/edit course page looking similar to "Add activity" with help text for each format

Course sections management

  • ? Add events_triggers in functions that create/delete/hide/move course sections
  • Refactor class editsection_form so it is easier to overwrite and implements functions set_data() and get_data() instead of pre/post processing data in editsection.php

Add course formats as plugin to site administration

Course formats are plugins in the code, but they are not handled as plugins in the administration. Replace course default settings by this page. Move page to plugins.

  • option to enable/disable a course format
  • each course format may have it's own configurable options such as default and/or sticky blocks, default settings, etc.

Other changes related to course formats

  • Make sure backup/restore correctly works with sections hierarchy and new options. Also backup made in previous versions restores correctly in 2.4
  • Make sure course format can influence navigation menu and breadcrumb. This probably will be done already by set_course/set_cm callbacks
  • Course formats may want to extend course settings navigation. Implement additional callback or do it in set_course() ?
  • Improvement: file_info (Server files repository) should list modules inside the course groupped by sections
  • Describe in course formats dev documentation how formats can watch the events triggers

Changes to course-related functions in 2.4

(see MDL-35339)

  • add function get_module_types_names() to replace $modnames and $modnamesplural in get_all_mods()
  • add course_modinfo::get_used_module_types() to replace $modnamesused in get_all_mods()
  • deprecate function get_all_mods(), change it's usage
  • deprecate function get_all_sections()
  • deprecate add_mod_to_section() and replace it with course_add_cm_to_section() to fix the mess in arguments

Comments to the changes of the specification

During actual development the specification was changed a little.

  • table course_sections will not have additional fields 'parent' and 'visibilityold'. If course format wants to support hierarchy, they should be defined as additional format options. There will be no performance change if we add those fields to the course_sections table because the information about all sections is cached anyway in course.sectioncache and should be accessed only using get_fast_modinfo()
  • there is no need in trigger 'course_format_changed' because there is already a trigger 'course_updated' and before it the format_base::update_course_format_options() is called with the before-update value of $course object
  • field course.format has the length 21 because if format wants to define it's own tables the table name should start with 'format_FORMATNAME' and at the same time it's name should not be longer than 28 symbols. Therefore there is 21 char left for FORMATNAME
  • function format_base::is_setup_completed() is not necessary because this functionality can be done in page_set_course() hook.


  • Add field course_module.sortorder and deprecate course_section.sequence (not in 2.4!)

Class course (for discussion, NOT for 2.4)

There are number of course-related functions in the core with random names. The argument name/property 'section' is used for both {section}.id and {section}.section, sometimes even the same variable changes it's meaning. Some very important functions completely miss phpdocs.

Besides it will be more understandable for developers of modules and other plugins to relate to course object and not to course format (for example to get section name, etc.)

The proposal is:

  • move code of all those functions into new class 'course'
  • leave the functions themselves in course/deprecatedlib.php with developer warning and call to corresponding function from course class
  • update usage of those functions in the core
  • add function get_course() or course_get_course() to retrieve the cached instance of the course, make sure cache is emptied inside rebuid_course_cache()
  • try to replace multiple similar queries $DB->get_record('course', array('id'=>$courseid)) in the core code

Source of course/lib.php:

Existing function New function
get_fast_modinfo() ? course::get_modinfo()
get_array_of_activities() course::get_array_of_activities() [used only by get_fast_modinfo()]
course_set_marker() course::set_marker()
set_section_visible course::set_section_visible()
add_course_module() course::add_cm_raw() This function only creates an entry in table {course_module}
course_add_cm_to_section() course::cm_add_to_section()
- course::add_cm() calls previous two functions and rebuild_course_cache()
get_course_section() course::get_or_create_section() will return section_info
- course::get_section() will return section_info, alias to get_fast_modinfo()->get_section_info()
- course::get_sections() alias to get_fast_modinfo()->get_section_info_all()
set_coursemodule_groupmode() course::set_cm_groupmode()
set_coursemodule_idnumber() course::set_cm_idnumber()
set_coursemodule_visible() course::set_cm_visible()
delete_course_module() course::delete_cm_raw()
delete_mod_from_section() course::delete_cm_from_section()
- course::delete_cm() will call both previous functions
move_section_to() course::move_section(), also call rebuild_course_cache()
reorder_sections() course::reorder_sections(), also call rebuild_course_cache()
moveto_module() course::move_cm()
course_format_name() course::get_formatted_name()
get_section_name() format_base::get_section_name() with aliases: course::get_section_name() and section_info::get_name()
can_delete_course() course::can_delete()
create_course() course::create() [static]
update_course() course::update()
course_ajax_enabled() course::is_ajax_enabled()
include_course_ajax() course::include_ajax()
course_get_url() course::get_view_url()

Other course-related functions in course/lib.php

  • get_print_section_cm_text()
  • print_section()
  • print_section_add_menus()
  • get_module_metadata()
  • print_course
  • make_editing_buttons()
  • course_allowed_module()