MDL-62748 course: maxsections is a limit
[moodle.git] / course / format / lib.php
CommitLineData
ee7084e9
MG
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Base class for course format plugins
19 *
20 * @package core_course
21 * @copyright 2012 Marina Glancy
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die;
26
27/**
28 * Returns an instance of format class (extending format_base) for given course
29 *
30 * @param int|stdClass $courseorid either course id or
31 * an object that has the property 'format' and may contain property 'id'
32 * @return format_base
33 */
34function course_get_format($courseorid) {
35 return format_base::instance($courseorid);
36}
37
38/**
39 * Base class for course formats
40 *
41 * Each course format must declare class
42 * class format_FORMATNAME extends format_base {}
43 * in file lib.php
44 *
45 * For each course just one instance of this class is created and it will always be returned by
46 * course_get_format($courseorid). Format may store it's specific course-dependent options in
47 * variables of this class.
48 *
49 * In rare cases instance of child class may be created just for format without course id
50 * i.e. to check if format supports AJAX.
51 *
52 * Also course formats may extend class section_info and overwrite
53 * format_base::build_section_cache() to return more information about sections.
54 *
55 * If you are upgrading from Moodle 2.3 start with copying the class format_legacy and renaming
56 * it to format_FORMATNAME, then move the code from your callback functions into
57 * appropriate functions of the class.
58 *
59 * @package core_course
60 * @copyright 2012 Marina Glancy
61 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
62 */
63abstract class format_base {
64 /** @var int Id of the course in this instance (maybe 0) */
65 protected $courseid;
66 /** @var string format used for this course. Please note that it can be different from
67 * course.format field if course referes to non-existing of disabled format */
68 protected $format;
69 /** @var stdClass data for course object, please use {@link format_base::get_course()} */
70 protected $course = false;
fc79ede5
MG
71 /** @var array caches format options, please use {@link format_base::get_format_options()} */
72 protected $formatoptions = array();
ee7084e9
MG
73 /** @var array cached instances */
74 private static $instances = array();
6382060d
TH
75 /** @var array plugin name => class name. */
76 private static $classesforformat = array('site' => 'site');
ee7084e9
MG
77
78 /**
79 * Creates a new instance of class
80 *
81 * Please use {@link course_get_format($courseorid)} to get an instance of the format class
82 *
83 * @param string $format
84 * @param int $courseid
85 * @return format_base
86 */
87 protected function __construct($format, $courseid) {
88 $this->format = $format;
89 $this->courseid = $courseid;
90 }
91
92 /**
76ab3fa1 93 * Validates that course format exists and enabled and returns either itself or default format
ee7084e9
MG
94 *
95 * @param string $format
96 * @return string
97 */
76ab3fa1 98 protected static final function get_format_or_default($format) {
5e4f1cff
MG
99 global $CFG;
100 require_once($CFG->dirroot . '/course/lib.php');
101
6382060d
TH
102 if (array_key_exists($format, self::$classesforformat)) {
103 return self::$classesforformat[$format];
ee7084e9 104 }
6382060d 105
3776335c 106 $plugins = get_sorted_course_formats();
6382060d
TH
107 foreach ($plugins as $plugin) {
108 self::$classesforformat[$plugin] = $plugin;
109 }
110
111 if (array_key_exists($format, self::$classesforformat)) {
112 return self::$classesforformat[$format];
ee7084e9 113 }
6382060d 114
daad1b4b
MG
115 if (PHPUNIT_TEST && class_exists('format_' . $format)) {
116 // Allow unittests to use non-existing course formats.
117 return $format;
118 }
119
ee7084e9 120 // Else return default format
3776335c
MG
121 $defaultformat = get_config('moodlecourse', 'format');
122 if (!in_array($defaultformat, $plugins)) {
123 // when default format is not set correctly, use the first available format
124 $defaultformat = reset($plugins);
125 }
6382060d
TH
126 debugging('Format plugin format_'.$format.' is not found. Using default format_'.$defaultformat, DEBUG_DEVELOPER);
127
128 self::$classesforformat[$format] = $defaultformat;
ee7084e9
MG
129 return $defaultformat;
130 }
131
132 /**
133 * Get class name for the format
134 *
135 * If course format xxx does not declare class format_xxx, format_legacy will be returned.
136 * This function also includes lib.php file from corresponding format plugin
137 *
138 * @param string $format
139 * @return string
140 */
141 protected static final function get_class_name($format) {
142 global $CFG;
143 static $classnames = array('site' => 'format_site');
144 if (!isset($classnames[$format])) {
bd3b3bba 145 $plugins = core_component::get_plugin_list('format');
76ab3fa1 146 $usedformat = self::get_format_or_default($format);
daad1b4b 147 if (isset($plugins[$usedformat]) && file_exists($plugins[$usedformat].'/lib.php')) {
76ab3fa1 148 require_once($plugins[$usedformat].'/lib.php');
ee7084e9
MG
149 }
150 $classnames[$format] = 'format_'. $usedformat;
151 if (!class_exists($classnames[$format])) {
76ab3fa1 152 require_once($CFG->dirroot.'/course/format/formatlegacy.php');
ee7084e9
MG
153 $classnames[$format] = 'format_legacy';
154 }
155 }
156 return $classnames[$format];
157 }
158
159 /**
160 * Returns an instance of the class
161 *
76ab3fa1 162 * @todo MDL-35727 use MUC for caching of instances, limit the number of cached instances
ee7084e9
MG
163 *
164 * @param int|stdClass $courseorid either course id or
165 * an object that has the property 'format' and may contain property 'id'
166 * @return format_base
167 */
168 public static final function instance($courseorid) {
169 global $DB;
170 if (!is_object($courseorid)) {
171 $courseid = (int)$courseorid;
172 if ($courseid && isset(self::$instances[$courseid]) && count(self::$instances[$courseid]) == 1) {
76ab3fa1
MG
173 $formats = array_keys(self::$instances[$courseid]);
174 $format = reset($formats);
ee7084e9
MG
175 } else {
176 $format = $DB->get_field('course', 'format', array('id' => $courseid), MUST_EXIST);
177 }
178 } else {
179 $format = $courseorid->format;
180 if (isset($courseorid->id)) {
76ab3fa1 181 $courseid = clean_param($courseorid->id, PARAM_INT);
ee7084e9
MG
182 } else {
183 $courseid = 0;
184 }
185 }
186 // validate that format exists and enabled, use default otherwise
76ab3fa1 187 $format = self::get_format_or_default($format);
ee7084e9
MG
188 if (!isset(self::$instances[$courseid][$format])) {
189 $classname = self::get_class_name($format);
190 self::$instances[$courseid][$format] = new $classname($format, $courseid);
191 }
192 return self::$instances[$courseid][$format];
193 }
194
195 /**
196 * Resets cache for the course (or all caches)
197 * To be called from {@link rebuild_course_cache()}
198 *
199 * @param int $courseid
200 */
201 public static final function reset_course_cache($courseid = 0) {
202 if ($courseid) {
203 if (isset(self::$instances[$courseid])) {
204 foreach (self::$instances[$courseid] as $format => $object) {
205 // in case somebody keeps the reference to course format object
206 self::$instances[$courseid][$format]->course = false;
fc79ede5 207 self::$instances[$courseid][$format]->formatoptions = array();
ee7084e9
MG
208 }
209 unset(self::$instances[$courseid]);
210 }
211 } else {
212 self::$instances = array();
213 }
214 }
215
216 /**
217 * Returns the format name used by this course
218 *
219 * @return string
220 */
76ab3fa1 221 public final function get_format() {
ee7084e9
MG
222 return $this->format;
223 }
224
225 /**
226 * Returns id of the course (0 if course is not specified)
227 *
228 * @return int
229 */
76ab3fa1 230 public final function get_courseid() {
ee7084e9
MG
231 return $this->courseid;
232 }
233
234 /**
235 * Returns a record from course database table plus additional fields
236 * that course format defines
237 *
238 * @return stdClass
239 */
240 public function get_course() {
241 global $DB;
242 if (!$this->courseid) {
243 return null;
244 }
245 if ($this->course === false) {
a2602457 246 $this->course = get_course($this->courseid);
fc79ede5 247 $options = $this->get_format_options();
7456c967 248 $dbcoursecolumns = null;
fc79ede5 249 foreach ($options as $optionname => $optionvalue) {
7456c967
MG
250 if (isset($this->course->$optionname)) {
251 // Course format options must not have the same names as existing columns in db table "course".
252 if (!isset($dbcoursecolumns)) {
253 $dbcoursecolumns = $DB->get_columns('course');
254 }
255 if (isset($dbcoursecolumns[$optionname])) {
256 debugging('The option name '.$optionname.' in course format '.$this->format.
257 ' is invalid because the field with the same name exists in {course} table',
258 DEBUG_DEVELOPER);
259 continue;
260 }
fc79ede5 261 }
7456c967 262 $this->course->$optionname = $optionvalue;
fc79ede5 263 }
ee7084e9
MG
264 }
265 return $this->course;
266 }
267
89b909f6
MG
268 /**
269 * Method used in the rendered and during backup instead of legacy 'numsections'
270 *
271 * Default renderer will treat sections with sectionnumber greater that the value returned by this
272 * method as "orphaned" and not display them on the course page unless in editing mode.
273 * Backup will store this value as 'numsections'.
274 *
275 * This method ensures that 3rd party course format plugins that still use 'numsections' continue to
276 * work but at the same time we no longer expect formats to have 'numsections' property.
277 *
278 * @return int
279 */
280 public function get_last_section_number() {
281 $course = $this->get_course();
282 if (isset($course->numsections)) {
283 return $course->numsections;
284 }
285 $modinfo = get_fast_modinfo($course);
286 $sections = $modinfo->get_section_info_all();
287 return (int)max(array_keys($sections));
288 }
289
7c05d8a3
DW
290 /**
291 * Method used to get the maximum number of sections for this course format.
292 * @return int
293 */
294 public function get_max_sections() {
295 $maxsections = get_config('moodlecourse', 'maxsections');
296 if (!isset($maxsections) || !is_numeric($maxsections)) {
297 $maxsections = 52;
298 }
299 return $maxsections;
300 }
301
d9203fb7
FM
302 /**
303 * Returns true if the course has a front page.
304 *
305 * This function is called to determine if the course has a view page, whether or not
306 * it contains a listing of activities. It can be useful to set this to false when the course
307 * format has only one activity and ignores the course page. Or if there are multiple
308 * activities but no page to see the centralised information.
309 *
310 * Initially this was created to know if forms should add a button to return to the course page.
311 * So if 'Return to course' does not make sense in your format your should probably return false.
312 *
313 * @return boolean
5bcfd504 314 * @since Moodle 2.6
d9203fb7
FM
315 */
316 public function has_view_page() {
317 return true;
318 }
319
ee7084e9
MG
320 /**
321 * Returns true if this course format uses sections
322 *
323 * This function may be called without specifying the course id
324 * i.e. in {@link course_format_uses_sections()}
325 *
326 * Developers, note that if course format does use sections there should be defined a language
327 * string with the name 'sectionname' defining what the section relates to in the format, i.e.
328 * $string['sectionname'] = 'Topic';
329 * or
330 * $string['sectionname'] = 'Week';
331 *
332 * @return bool
333 */
334 public function uses_sections() {
335 return false;
336 }
337
338 /**
339 * Returns a list of sections used in the course
340 *
341 * This is a shortcut to get_fast_modinfo()->get_section_info_all()
342 * @see get_fast_modinfo()
343 * @see course_modinfo::get_section_info_all()
344 *
345 * @return array of section_info objects
346 */
347 public final function get_sections() {
348 if ($course = $this->get_course()) {
349 $modinfo = get_fast_modinfo($course);
350 return $modinfo->get_section_info_all();
351 }
352 return array();
353 }
354
355 /**
356 * Returns information about section used in course
357 *
358 * @param int|stdClass $section either section number (field course_section.section) or row from course_section table
359 * @param int $strictness
360 * @return section_info
361 */
362 public final function get_section($section, $strictness = IGNORE_MISSING) {
363 if (is_object($section)) {
364 $sectionnum = $section->section;
365 } else {
366 $sectionnum = $section;
367 }
368 $sections = $this->get_sections();
369 if (array_key_exists($sectionnum, $sections)) {
370 return $sections[$sectionnum];
371 }
372 if ($strictness == MUST_EXIST) {
373 throw new moodle_exception('sectionnotexist');
374 }
375 return null;
376 }
377
378 /**
379 * Returns the display name of the given section that the course prefers.
380 *
381 * @param int|stdClass $section Section object from database or just field course_sections.section
382 * @return Display name that the course format prefers, e.g. "Topic 2"
383 */
384 public function get_section_name($section) {
385 if (is_object($section)) {
386 $sectionnum = $section->section;
387 } else {
388 $sectionnum = $section;
389 }
f1bfc897
JP
390
391 if (get_string_manager()->string_exists('sectionname', 'format_' . $this->format)) {
392 return get_string('sectionname', 'format_' . $this->format) . ' ' . $sectionnum;
393 }
394
395 // Return an empty string if there's no available section name string for the given format.
396 return '';
397 }
398
399 /**
400 * Returns the default section using format_base's implementation of get_section_name.
401 *
402 * @param int|stdClass $section Section object from database or just field course_sections section
403 * @return string The default value for the section name based on the given course format.
404 */
405 public function get_default_section_name($section) {
406 return self::get_section_name($section);
ee7084e9 407 }
76ab3fa1 408
ee7084e9
MG
409 /**
410 * Returns the information about the ajax support in the given source format
411 *
412 * The returned object's property (boolean)capable indicates that
413 * the course format supports Moodle course ajax features.
ee7084e9
MG
414 *
415 * @return stdClass
416 */
417 public function supports_ajax() {
418 // no support by default
419 $ajaxsupport = new stdClass();
420 $ajaxsupport->capable = false;
ee7084e9
MG
421 return $ajaxsupport;
422 }
423
424 /**
425 * Custom action after section has been moved in AJAX mode
426 *
427 * Used in course/rest.php
428 *
429 * @return array This will be passed in ajax respose
430 */
431 public function ajax_section_move() {
432 return null;
433 }
434
435 /**
436 * The URL to use for the specified course (with section)
437 *
438 * Please note that course view page /course/view.php?id=COURSEID is hardcoded in many
439 * places in core and contributed modules. If course format wants to change the location
440 * of the view script, it is not enough to change just this function. Do not forget
441 * to add proper redirection.
442 *
443 * @param int|stdClass $section Section object from database or just field course_sections.section
444 * if null the course view page is returned
445 * @param array $options options for view URL. At the moment core uses:
446 * 'navigation' (bool) if true and section has no separate page, the function returns null
447 * 'sr' (int) used by multipage formats to specify to which section to return
448 * @return null|moodle_url
449 */
450 public function get_view_url($section, $options = array()) {
53623a70 451 global $CFG;
ee7084e9
MG
452 $course = $this->get_course();
453 $url = new moodle_url('/course/view.php', array('id' => $course->id));
1872a0f2 454
ee7084e9 455 if (array_key_exists('sr', $options)) {
b5cf83f0
MG
456 $sectionno = $options['sr'];
457 } else if (is_object($section)) {
ee7084e9
MG
458 $sectionno = $section->section;
459 } else {
460 $sectionno = $section;
461 }
53623a70 462 if (empty($CFG->linkcoursesections) && !empty($options['navigation']) && $sectionno !== null) {
b5cf83f0
MG
463 // by default assume that sections are never displayed on separate pages
464 return null;
465 }
466 if ($this->uses_sections() && $sectionno !== null) {
467 $url->set_anchor('section-'.$sectionno);
ee7084e9
MG
468 }
469 return $url;
470 }
471
472 /**
473 * Loads all of the course sections into the navigation
474 *
e010b850
MG
475 * This method is called from {@link global_navigation::load_course_sections()}
476 *
ee7084e9
MG
477 * By default the method {@link global_navigation::load_generic_course_sections()} is called
478 *
e010b850
MG
479 * When overwriting please note that navigationlib relies on using the correct values for
480 * arguments $type and $key in {@link navigation_node::add()}
481 *
482 * Example of code creating a section node:
483 * $sectionnode = $node->add($sectionname, $url, navigation_node::TYPE_SECTION, null, $section->id);
484 * $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH;
485 *
486 * Example of code creating an activity node:
487 * $activitynode = $sectionnode->add($activityname, $action, navigation_node::TYPE_ACTIVITY, null, $activity->id, $icon);
488 * if (global_navigation::module_extends_navigation($activity->modname)) {
489 * $activitynode->nodetype = navigation_node::NODETYPE_BRANCH;
490 * } else {
491 * $activitynode->nodetype = navigation_node::NODETYPE_LEAF;
492 * }
493 *
494 * Also note that if $navigation->includesectionnum is not null, the section with this relative
495 * number needs is expected to be loaded
496 *
ee7084e9
MG
497 * @param global_navigation $navigation
498 * @param navigation_node $node The course node within the navigation
ee7084e9 499 */
e010b850 500 public function extend_course_navigation($navigation, navigation_node $node) {
ee7084e9 501 if ($course = $this->get_course()) {
e010b850 502 $navigation->load_generic_course_sections($course, $node);
ee7084e9
MG
503 }
504 return array();
505 }
a49e2ea7
MG
506
507 /**
508 * Returns the list of blocks to be automatically added for the newly created course
509 *
510 * @see blocks_add_default_course_blocks()
511 *
512 * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT
513 * each of values is an array of block names (for left and right side columns)
514 */
515 public function get_default_blocks() {
516 global $CFG;
4582da24 517 if (isset($CFG->defaultblocks)) {
a49e2ea7
MG
518 return blocks_parse_default_blocks_list($CFG->defaultblocks);
519 }
520 $blocknames = array(
521 BLOCK_POS_LEFT => array(),
c13115cb 522 BLOCK_POS_RIGHT => array()
a49e2ea7
MG
523 );
524 return $blocknames;
525 }
fc79ede5
MG
526
527 /**
528 * Returns the localised name of this course format plugin
529 *
530 * @return lang_string
531 */
532 public final function get_format_name() {
533 return new lang_string('pluginname', 'format_'.$this->get_format());
534 }
535
536 /**
537 * Definitions of the additional options that this course format uses for course
538 *
539 * This function may be called often, it should be as fast as possible.
540 * Avoid using get_string() method, use "new lang_string()" instead
541 * It is not recommended to use dynamic or course-dependant expressions here
542 * This function may be also called when course does not exist yet.
543 *
544 * Option names must be different from fields in the {course} talbe or any form elements on
545 * course edit form, it may even make sence to use special prefix for them.
546 *
547 * Each option must have the option name as a key and the array of properties as a value:
aea2e3c3 548 * 'default' - default value for this option (assumed null if not specified)
fc79ede5 549 * 'type' - type of the option value (PARAM_INT, PARAM_RAW, etc.)
aea2e3c3
MG
550 *
551 * Additional properties used by default implementation of
552 * {@link format_base::create_edit_form_elements()} (calls this method with $foreditform = true)
553 * 'label' - localised human-readable label for the edit form
fc79ede5
MG
554 * 'element_type' - type of the form element, default 'text'
555 * 'element_attributes' - additional attributes for the form element, these are 4th and further
556 * arguments in the moodleform::addElement() method
557 * 'help' - string for help button. Note that if 'help' value is 'myoption' then the string with
558 * the name 'myoption_help' must exist in the language file
559 * 'help_component' - language component to look for help string, by default this the component
560 * for this course format
561 *
fc79ede5
MG
562 * This is an interface for creating simple form elements. If format plugin wants to use other
563 * methods such as disableIf, it can be done by overriding create_edit_form_elements().
564 *
aea2e3c3
MG
565 * Course format options can be accessed as:
566 * $this->get_course()->OPTIONNAME (inside the format class)
567 * course_get_format($course)->get_course()->OPTIONNAME (outside of format class)
568 *
569 * All course options are returned by calling:
570 * $this->get_format_options();
571 *
fc79ede5
MG
572 * @param bool $foreditform
573 * @return array of options
574 */
575 public function course_format_options($foreditform = false) {
576 return array();
577 }
578
579 /**
580 * Definitions of the additional options that this course format uses for section
581 *
582 * See {@link format_base::course_format_options()} for return array definition.
583 *
584 * Additionally section format options may have property 'cache' set to true
585 * if this option needs to be cached in {@link get_fast_modinfo()}. The 'cache' property
586 * is recommended to be set only for fields used in {@link format_base::get_section_name()},
587 * {@link format_base::extend_course_navigation()} and {@link format_base::get_view_url()}
588 *
aea2e3c3
MG
589 * For better performance cached options are recommended to have 'cachedefault' property
590 * Unlike 'default', 'cachedefault' should be static and not access get_config().
591 *
592 * Regardless of value of 'cache' all options are accessed in the code as
593 * $sectioninfo->OPTIONNAME
594 * where $sectioninfo is instance of section_info, returned by
595 * get_fast_modinfo($course)->get_section_info($sectionnum)
596 * or get_fast_modinfo($course)->get_section_info_all()
597 *
598 * All format options for particular section are returned by calling:
599 * $this->get_format_options($section);
600 *
fc79ede5
MG
601 * @param bool $foreditform
602 * @return array
603 */
604 public function section_format_options($foreditform = false) {
605 return array();
606 }
607
608 /**
609 * Returns the format options stored for this course or course section
610 *
aea2e3c3
MG
611 * When overriding please note that this function is called from rebuild_course_cache()
612 * and section_info object, therefore using of get_fast_modinfo() and/or any function that
613 * accesses it may lead to recursion.
614 *
fc79ede5
MG
615 * @param null|int|stdClass|section_info $section if null the course format options will be returned
616 * otherwise options for specified section will be returned. This can be either
617 * section object or relative section number (field course_sections.section)
618 * @return array
619 */
620 public function get_format_options($section = null) {
621 global $DB;
622 if ($section === null) {
623 $options = $this->course_format_options();
624 } else {
625 $options = $this->section_format_options();
626 }
627 if (empty($options)) {
628 // there are no option for course/sections anyway, no need to go further
629 return array();
630 }
631 if ($section === null) {
632 // course format options will be returned
633 $sectionid = 0;
634 } else if ($this->courseid && isset($section->id)) {
635 // course section format options will be returned
636 $sectionid = $section->id;
aea2e3c3
MG
637 } else if ($this->courseid && is_int($section) &&
638 ($sectionobj = $DB->get_record('course_sections',
6382c482 639 array('section' => $section, 'course' => $this->courseid), 'id'))) {
fc79ede5
MG
640 // course section format options will be returned
641 $sectionid = $sectionobj->id;
642 } else {
643 // non-existing (yet) section was passed as an argument
644 // default format options for course section will be returned
645 $sectionid = -1;
646 }
647 if (!array_key_exists($sectionid, $this->formatoptions)) {
648 $this->formatoptions[$sectionid] = array();
649 // first fill with default values
650 foreach ($options as $optionname => $optionparams) {
651 $this->formatoptions[$sectionid][$optionname] = null;
652 if (array_key_exists('default', $optionparams)) {
653 $this->formatoptions[$sectionid][$optionname] = $optionparams['default'];
654 }
655 }
656 if ($this->courseid && $sectionid !== -1) {
657 // overwrite the default options values with those stored in course_format_options table
658 // nothing can be stored if we are interested in generic course ($this->courseid == 0)
659 // or generic section ($sectionid === 0)
660 $records = $DB->get_records('course_format_options',
661 array('courseid' => $this->courseid,
662 'format' => $this->format,
663 'sectionid' => $sectionid
664 ), '', 'id,name,value');
665 foreach ($records as $record) {
666 if (array_key_exists($record->name, $this->formatoptions[$sectionid])) {
667 $value = $record->value;
668 if ($value !== null && isset($options[$record->name]['type'])) {
669 // this will convert string value to number if needed
670 $value = clean_param($value, $options[$record->name]['type']);
671 }
672 $this->formatoptions[$sectionid][$record->name] = $value;
673 }
674 }
675 }
676 }
677 return $this->formatoptions[$sectionid];
678 }
679
680 /**
681 * Adds format options elements to the course/section edit form
682 *
683 * This function is called from {@link course_edit_form::definition_after_data()}
684 *
92d38668 685 * @param MoodleQuickForm $mform form the elements are added to
fc79ede5
MG
686 * @param bool $forsection 'true' if this is a section edit form, 'false' if this is course edit form
687 * @return array array of references to the added form elements
688 */
689 public function create_edit_form_elements(&$mform, $forsection = false) {
690 $elements = array();
691 if ($forsection) {
692 $options = $this->section_format_options(true);
693 } else {
694 $options = $this->course_format_options(true);
695 }
696 foreach ($options as $optionname => $option) {
697 if (!isset($option['element_type'])) {
698 $option['element_type'] = 'text';
699 }
700 $args = array($option['element_type'], $optionname, $option['label']);
701 if (!empty($option['element_attributes'])) {
702 $args = array_merge($args, $option['element_attributes']);
703 }
6b02cc4f 704 $elements[] = call_user_func_array(array($mform, 'addElement'), $args);
fc79ede5
MG
705 if (isset($option['help'])) {
706 $helpcomponent = 'format_'. $this->get_format();
707 if (isset($option['help_component'])) {
708 $helpcomponent = $option['help_component'];
709 }
710 $mform->addHelpButton($optionname, $option['help'], $helpcomponent);
711 }
712 if (isset($option['type'])) {
713 $mform->setType($optionname, $option['type']);
714 }
aef5c363
MG
715 if (isset($option['default']) && !array_key_exists($optionname, $mform->_defaultValues)) {
716 // Set defaults for the elements in the form.
717 // Since we call this method after set_data() make sure that we don't override what was already set.
fc79ede5
MG
718 $mform->setDefault($optionname, $option['default']);
719 }
720 }
8643c576
DM
721
722 if (!$forsection && empty($this->courseid)) {
33a3ec7c
AB
723 // Check if course end date form field should be enabled by default.
724 // If a default date is provided to the form element, it is magically enabled by default in the
725 // MoodleQuickForm_date_time_selector class, otherwise it's disabled by default.
726 if (get_config('moodlecourse', 'courseenddateenabled')) {
727 // At this stage (this is called from definition_after_data) course data is already set as default.
728 // We can not overwrite what is in the database.
729 $mform->setDefault('enddate', $this->get_default_course_enddate($mform));
730 }
8643c576
DM
731 }
732
fc79ede5
MG
733 return $elements;
734 }
735
736 /**
737 * Override if you need to perform some extra validation of the format options
738 *
739 * @param array $data array of ("fieldname"=>value) of submitted data
740 * @param array $files array of uploaded files "element_name"=>tmp_file_path
741 * @param array $errors errors already discovered in edit form validation
742 * @return array of "element_name"=>"error_description" if there are errors,
743 * or an empty array if everything is OK.
744 * Do not repeat errors from $errors param here
745 */
746 public function edit_form_validation($data, $files, $errors) {
747 return array();
748 }
749
a589b992
MG
750 /**
751 * Prepares values of course or section format options before storing them in DB
752 *
753 * If an option has invalid value it is not returned
754 *
755 * @param array $rawdata associative array of the proposed course/section format options
756 * @param int|null $sectionid null if it is course format option
757 * @return array array of options that have valid values
758 */
759 protected function validate_format_options(array $rawdata, int $sectionid = null) : array {
760 if (!$sectionid) {
761 $allformatoptions = $this->course_format_options(true);
762 } else {
763 $allformatoptions = $this->section_format_options(true);
764 }
765 $data = array_intersect_key($rawdata, $allformatoptions);
766 foreach ($data as $key => $value) {
767 $option = $allformatoptions[$key] + ['type' => PARAM_RAW, 'element_type' => null, 'element_attributes' => [[]]];
768 $data[$key] = clean_param($value, $option['type']);
769 if ($option['element_type'] === 'select' && !array_key_exists($data[$key], $option['element_attributes'][0])) {
770 // Value invalid for select element, skip.
771 unset($data[$key]);
772 }
773 }
774 return $data;
775 }
776
777 /**
778 * Validates format options for the course
779 *
780 * @param array $data data to insert/update
781 * @return array array of options that have valid values
782 */
783 public function validate_course_format_options(array $data) : array {
784 return $this->validate_format_options($data);
785 }
786
fc79ede5
MG
787 /**
788 * Updates format options for a course or section
789 *
790 * If $data does not contain property with the option name, the option will not be updated
791 *
792 * @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data
793 * @param null|int null if these are options for course or section id (course_sections.id)
794 * if these are options for section
795 * @return bool whether there were any changes to the options values
796 */
797 protected function update_format_options($data, $sectionid = null) {
798 global $DB;
a589b992 799 $data = $this->validate_format_options((array)$data, $sectionid);
fc79ede5
MG
800 if (!$sectionid) {
801 $allformatoptions = $this->course_format_options();
802 $sectionid = 0;
803 } else {
804 $allformatoptions = $this->section_format_options();
805 }
806 if (empty($allformatoptions)) {
807 // nothing to update anyway
808 return false;
809 }
810 $defaultoptions = array();
811 $cached = array();
812 foreach ($allformatoptions as $key => $option) {
813 $defaultoptions[$key] = null;
814 if (array_key_exists('default', $option)) {
815 $defaultoptions[$key] = $option['default'];
816 }
817 $cached[$key] = ($sectionid === 0 || !empty($option['cache']));
818 }
819 $records = $DB->get_records('course_format_options',
820 array('courseid' => $this->courseid,
821 'format' => $this->format,
822 'sectionid' => $sectionid
823 ), '', 'name,id,value');
824 $changed = $needrebuild = false;
fc79ede5
MG
825 foreach ($defaultoptions as $key => $value) {
826 if (isset($records[$key])) {
827 if (array_key_exists($key, $data) && $records[$key]->value !== $data[$key]) {
828 $DB->set_field('course_format_options', 'value',
829 $data[$key], array('id' => $records[$key]->id));
830 $changed = true;
831 $needrebuild = $needrebuild || $cached[$key];
832 }
833 } else {
834 if (array_key_exists($key, $data) && $data[$key] !== $value) {
835 $newvalue = $data[$key];
836 $changed = true;
837 $needrebuild = $needrebuild || $cached[$key];
838 } else {
839 $newvalue = $value;
840 // we still insert entry in DB but there are no changes from user point of
841 // view and no need to call rebuild_course_cache()
842 }
843 $DB->insert_record('course_format_options', array(
844 'courseid' => $this->courseid,
845 'format' => $this->format,
846 'sectionid' => $sectionid,
847 'name' => $key,
848 'value' => $newvalue
849 ));
850 }
851 }
852 if ($needrebuild) {
853 rebuild_course_cache($this->courseid, true);
854 }
855 if ($changed) {
856 // reset internal caches
857 if (!$sectionid) {
858 $this->course = false;
859 }
860 unset($this->formatoptions[$sectionid]);
861 }
862 return $changed;
863 }
864
865 /**
866 * Updates format options for a course
867 *
868 * If $data does not contain property with the option name, the option will not be updated
869 *
870 * @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data
871 * @param stdClass $oldcourse if this function is called from {@link update_course()}
872 * this object contains information about the course before update
873 * @return bool whether there were any changes to the options values
874 */
875 public function update_course_format_options($data, $oldcourse = null) {
876 return $this->update_format_options($data);
877 }
878
879 /**
880 * Updates format options for a section
881 *
882 * Section id is expected in $data->id (or $data['id'])
883 * If $data does not contain property with the option name, the option will not be updated
884 *
885 * @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data
886 * @return bool whether there were any changes to the options values
887 */
888 public function update_section_format_options($data) {
889 $data = (array)$data;
890 return $this->update_format_options($data, $data['id']);
891 }
892
893 /**
894 * Return an instance of moodleform to edit a specified section
895 *
896 * Default implementation returns instance of editsection_form that automatically adds
897 * additional fields defined in {@link format_base::section_format_options()}
898 *
899 * Format plugins may extend editsection_form if they want to have custom edit section form.
900 *
901 * @param mixed $action the action attribute for the form. If empty defaults to auto detect the
902 * current url. If a moodle_url object then outputs params as hidden variables.
903 * @param array $customdata the array with custom data to be passed to the form
904 * /course/editsection.php passes section_info object in 'cs' field
905 * for filling availability fields
906 * @return moodleform
907 */
908 public function editsection_form($action, $customdata = array()) {
909 global $CFG;
910 require_once($CFG->dirroot. '/course/editsection_form.php');
911 $context = context_course::instance($this->courseid);
912 if (!array_key_exists('course', $customdata)) {
913 $customdata['course'] = $this->get_course();
914 }
915 return new editsection_form($action, $customdata);
916 }
4b5a6b13 917
695705f5
MG
918 /**
919 * Allows course format to execute code on moodle_page::set_course()
920 *
921 * @param moodle_page $page instance of page calling set_course
922 */
923 public function page_set_course(moodle_page $page) {
924 }
925
926 /**
927 * Allows course format to execute code on moodle_page::set_cm()
928 *
929 * Current module can be accessed as $page->cm (returns instance of cm_info)
930 *
931 * @param moodle_page $page instance of page calling set_cm
932 */
933 public function page_set_cm(moodle_page $page) {
934 }
5ef23705
MG
935
936 /**
937 * Course-specific information to be output on any course page (usually above navigation bar)
938 *
939 * Example of usage:
940 * define
941 * class format_FORMATNAME_XXX implements renderable {}
942 *
943 * create format renderer in course/format/FORMATNAME/renderer.php, define rendering function:
944 * class format_FORMATNAME_renderer extends plugin_renderer_base {
945 * protected function render_format_FORMATNAME_XXX(format_FORMATNAME_XXX $xxx) {
946 * return html_writer::tag('div', 'This is my header/footer');
947 * }
948 * }
949 *
950 * Return instance of format_FORMATNAME_XXX in this function, the appropriate method from
951 * plugin renderer will be called
952 *
953 * @return null|renderable null for no output or object with data for plugin renderer
954 */
955 public function course_header() {
956 return null;
957 }
958
959 /**
960 * Course-specific information to be output on any course page (usually in the beginning of
961 * standard footer)
962 *
963 * See {@link format_base::course_header()} for usage
964 *
965 * @return null|renderable null for no output or object with data for plugin renderer
966 */
967 public function course_footer() {
968 return null;
969 }
970
971 /**
972 * Course-specific information to be output immediately above content on any course page
973 *
974 * See {@link format_base::course_header()} for usage
975 *
976 * @return null|renderable null for no output or object with data for plugin renderer
977 */
978 public function course_content_header() {
979 return null;
980 }
981
982 /**
983 * Course-specific information to be output immediately below content on any course page
984 *
985 * See {@link format_base::course_header()} for usage
986 *
987 * @return null|renderable null for no output or object with data for plugin renderer
988 */
989 public function course_content_footer() {
990 return null;
991 }
992
993 /**
994 * Returns instance of page renderer used by this plugin
995 *
996 * @param moodle_page $page
997 * @return renderer_base
998 */
999 public function get_renderer(moodle_page $page) {
1000 return $page->get_renderer('format_'. $this->get_format());
1001 }
081c8f7f
MG
1002
1003 /**
1004 * Returns true if the specified section is current
1005 *
1006 * By default we analyze $course->marker
1007 *
1008 * @param int|stdClass|section_info $section
1009 * @return bool
1010 */
1011 public function is_section_current($section) {
1012 if (is_object($section)) {
1013 $sectionnum = $section->section;
1014 } else {
1015 $sectionnum = $section;
1016 }
1017 return ($sectionnum && ($course = $this->get_course()) && $course->marker == $sectionnum);
1018 }
daad1b4b
MG
1019
1020 /**
1021 * Allows to specify for modinfo that section is not available even when it is visible and conditionally available.
1022 *
1023 * Note: affected user can be retrieved as: $section->modinfo->userid
1024 *
1025 * Course format plugins can override the method to change the properties $available and $availableinfo that were
1026 * calculated by conditional availability.
1027 * To make section unavailable set:
1028 * $available = false;
1029 * To make unavailable section completely hidden set:
1030 * $availableinfo = '';
1031 * To make unavailable section visible with availability message set:
1032 * $availableinfo = get_string('sectionhidden', 'format_xxx');
1033 *
1034 * @param section_info $section
1035 * @param bool $available the 'available' propery of the section_info as it was evaluated by conditional availability.
1036 * Can be changed by the method but 'false' can not be overridden by 'true'.
1037 * @param string $availableinfo the 'availableinfo' propery of the section_info as it was evaluated by conditional availability.
1038 * Can be changed by the method
1039 */
1040 public function section_get_available_hook(section_info $section, &$available, &$availableinfo) {
1041 }
ca9cae84
MG
1042
1043 /**
1044 * Whether this format allows to delete sections
1045 *
1046 * If format supports deleting sections it is also recommended to define language string
1047 * 'deletesection' inside the format.
1048 *
1049 * Do not call this function directly, instead use {@link course_can_delete_section()}
1050 *
1051 * @param int|stdClass|section_info $section
1052 * @return bool
1053 */
1054 public function can_delete_section($section) {
1055 return false;
1056 }
1057
1058 /**
1059 * Deletes a section
1060 *
1061 * Do not call this function directly, instead call {@link course_delete_section()}
1062 *
1063 * @param int|stdClass|section_info $section
1064 * @param bool $forcedeleteifnotempty if set to false section will not be deleted if it has modules in it.
1065 * @return bool whether section was deleted
1066 */
1067 public function delete_section($section, $forcedeleteifnotempty = false) {
1068 global $DB;
1069 if (!$this->uses_sections()) {
1070 // Not possible to delete section if sections are not used.
1071 return false;
1072 }
1073 if (!is_object($section)) {
1074 $section = $DB->get_record('course_sections', array('course' => $this->get_courseid(), 'section' => $section),
5e717d10 1075 'id,section,sequence,summary');
ca9cae84
MG
1076 }
1077 if (!$section || !$section->section) {
1078 // Not possible to delete 0-section.
1079 return false;
1080 }
1081
5e717d10 1082 if (!$forcedeleteifnotempty && (!empty($section->sequence) || !empty($section->summary))) {
ca9cae84
MG
1083 return false;
1084 }
1085
1086 $course = $this->get_course();
1087
1088 // Remove the marker if it points to this section.
1089 if ($section->section == $course->marker) {
1090 course_set_marker($course->id, 0);
1091 }
1092
1093 $lastsection = $DB->get_field_sql('SELECT max(section) from {course_sections}
1094 WHERE course = ?', array($course->id));
1095
1096 // Find out if we need to descrease the 'numsections' property later.
1097 $courseformathasnumsections = array_key_exists('numsections',
1098 $this->get_format_options());
1099 $decreasenumsections = $courseformathasnumsections && ($section->section <= $course->numsections);
1100
1101 // Move the section to the end.
1102 move_section_to($course, $section->section, $lastsection, true);
1103
1104 // Delete all modules from the section.
1105 foreach (preg_split('/,/', $section->sequence, -1, PREG_SPLIT_NO_EMPTY) as $cmid) {
1106 course_delete_module($cmid);
1107 }
1108
1109 // Delete section and it's format options.
1110 $DB->delete_records('course_format_options', array('sectionid' => $section->id));
1111 $DB->delete_records('course_sections', array('id' => $section->id));
1112 rebuild_course_cache($course->id, true);
1113
1114 // Descrease 'numsections' if needed.
1115 if ($decreasenumsections) {
1116 $this->update_course_format_options(array('numsections' => $course->numsections - 1));
1117 }
1118
1119 return true;
1120 }
f26481c2
MG
1121
1122 /**
1123 * Prepares the templateable object to display section name
1124 *
1125 * @param \section_info|\stdClass $section
1126 * @param bool $linkifneeded
1127 * @param bool $editable
1128 * @param null|lang_string|string $edithint
1129 * @param null|lang_string|string $editlabel
1130 * @return \core\output\inplace_editable
1131 */
1132 public function inplace_editable_render_section_name($section, $linkifneeded = true,
1133 $editable = null, $edithint = null, $editlabel = null) {
1134 global $USER, $CFG;
1135 require_once($CFG->dirroot.'/course/lib.php');
1136
1137 if ($editable === null) {
1138 $editable = !empty($USER->editing) && has_capability('moodle/course:update',
1139 context_course::instance($section->course));
1140 }
1141
1142 $displayvalue = $title = get_section_name($section->course, $section);
1143 if ($linkifneeded) {
1144 // Display link under the section name if the course format setting is to display one section per page.
1145 $url = course_get_url($section->course, $section->section, array('navigation' => true));
1146 if ($url) {
1147 $displayvalue = html_writer::link($url, $title);
1148 }
1149 $itemtype = 'sectionname';
1150 } else {
1151 // If $linkifneeded==false, we never display the link (this is used when rendering the section header).
1152 // Itemtype 'sectionnamenl' (nl=no link) will tell the callback that link should not be rendered -
1153 // there is no other way callback can know where we display the section name.
1154 $itemtype = 'sectionnamenl';
1155 }
1156 if (empty($edithint)) {
1157 $edithint = new lang_string('editsectionname');
1158 }
1159 if (empty($editlabel)) {
1160 $editlabel = new lang_string('newsectionname', '', $title);
1161 }
1162
1163 return new \core\output\inplace_editable('format_' . $this->format, $itemtype, $section->id, $editable,
1164 $displayvalue, $section->name, $edithint, $editlabel);
1165 }
1166
1167 /**
1168 * Updates the value in the database and modifies this object respectively.
1169 *
1170 * ALWAYS check user permissions before performing an update! Throw exceptions if permissions are not sufficient
1171 * or value is not legit.
1172 *
1173 * @param stdClass $section
1174 * @param string $itemtype
1175 * @param mixed $newvalue
1176 * @return \core\output\inplace_editable
1177 */
1178 public function inplace_editable_update_section_name($section, $itemtype, $newvalue) {
1179 if ($itemtype === 'sectionname' || $itemtype === 'sectionnamenl') {
f26481c2 1180 $context = context_course::instance($section->course);
787ec240 1181 external_api::validate_context($context);
f26481c2
MG
1182 require_capability('moodle/course:update', $context);
1183
1184 $newtitle = clean_param($newvalue, PARAM_TEXT);
1185 if (strval($section->name) !== strval($newtitle)) {
1186 course_update_section($section->course, $section, array('name' => $newtitle));
1187 }
1188 return $this->inplace_editable_render_section_name($section, ($itemtype === 'sectionname'), true);
1189 }
1190 }
8643c576
DM
1191
1192
1193 /**
1194 * Returns the default end date value based on the start date.
1195 *
1196 * This is the default implementation for course formats, it is based on
1197 * moodlecourse/courseduration setting. Course formats like format_weeks for
1198 * example can overwrite this method and return a value based on their internal options.
1199 *
1200 * @param moodleform $mform
1201 * @param array $fieldnames The form - field names mapping.
1202 * @return int
1203 */
1204 public function get_default_course_enddate($mform, $fieldnames = array()) {
1205
1206 if (empty($fieldnames)) {
1207 $fieldnames = array('startdate' => 'startdate');
1208 }
1209
1210 $startdate = $this->get_form_start_date($mform, $fieldnames);
1211 $courseduration = intval(get_config('moodlecourse', 'courseduration'));
1212 if (!$courseduration) {
1213 // Default, it should be already set during upgrade though.
1214 $courseduration = YEARSECS;
1215 }
1216
1217 return $startdate + $courseduration;
1218 }
1219
87799e9f
JP
1220 /**
1221 * Indicates whether the course format supports the creation of the Announcements forum.
1222 *
1223 * For course format plugin developers, please override this to return true if you want the Announcements forum
1224 * to be created upon course creation.
1225 *
1226 * @return bool
1227 */
1228 public function supports_news() {
1229 // For backwards compatibility, check if default blocks include the news_items block.
1230 $defaultblocks = $this->get_default_blocks();
1231 foreach ($defaultblocks as $blocks) {
1232 if (in_array('news_items', $blocks)) {
1233 return true;
1234 }
1235 }
1236 // Return false by default.
1237 return false;
1238 }
1239
8643c576
DM
1240 /**
1241 * Get the start date value from the course settings page form.
1242 *
1243 * @param moodleform $mform
1244 * @param array $fieldnames The form - field names mapping.
1245 * @return int
1246 */
1247 protected function get_form_start_date($mform, $fieldnames) {
1248 $startdate = $mform->getElementValue($fieldnames['startdate']);
1249 return $mform->getElement($fieldnames['startdate'])->exportValue($startdate);
1250 }
8341055e
MG
1251
1252 /**
1253 * Returns whether this course format allows the activity to
1254 * have "triple visibility state" - visible always, hidden on course page but available, hidden.
1255 *
1256 * @param stdClass|cm_info $cm course module (may be null if we are displaying a form for adding a module)
1257 * @param stdClass|section_info $section section where this module is located or will be added to
1258 * @return bool
1259 */
1260 public function allow_stealth_module_visibility($cm, $section) {
1261 return false;
1262 }
1263
1264 /**
1265 * Callback used in WS core_course_edit_section when teacher performs an AJAX action on a section (show/hide)
1266 *
1267 * Access to the course is already validated in the WS but the callback has to make sure
1268 * that particular action is allowed by checking capabilities
1269 *
1270 * Course formats should register
1271 *
1272 * @param stdClass|section_info $section
1273 * @param string $action
1274 * @param int $sr
1275 * @return null|array|stdClass any data for the Javascript post-processor (must be json-encodeable)
1276 */
1277 public function section_action($section, $action, $sr) {
1278 global $PAGE;
1279 if (!$this->uses_sections() || !$section->section) {
1280 // No section actions are allowed if course format does not support sections.
1281 // No actions are allowed on the 0-section by default (overwrite in course format if needed).
1282 throw new moodle_exception('sectionactionnotsupported', 'core', null, s($action));
1283 }
1284
1285 $course = $this->get_course();
1286 $coursecontext = context_course::instance($course->id);
1287 switch($action) {
1288 case 'hide':
1289 case 'show':
1290 require_capability('moodle/course:sectionvisibility', $coursecontext);
1291 $visible = ($action === 'hide') ? 0 : 1;
1292 course_update_section($course, $section, array('visible' => $visible));
1293 break;
1294 default:
1295 throw new moodle_exception('sectionactionnotsupported', 'core', null, s($action));
1296 }
1297
1298 $modules = [];
1299
1300 $modinfo = get_fast_modinfo($course);
1301 $coursesections = $modinfo->sections;
1302 if (array_key_exists($section->section, $coursesections)) {
1303 $courserenderer = $PAGE->get_renderer('core', 'course');
1304 $completioninfo = new completion_info($course);
1305 foreach ($coursesections[$section->section] as $cmid) {
1306 $cm = $modinfo->get_cm($cmid);
1307 $modules[] = $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $sr);
1308 }
1309 }
1310
1311 return ['modules' => $modules];
1312 }
ef184ad6
JL
1313
1314 /**
1315 * Return the plugin config settings for external functions,
1316 * in some cases the configs will need formatting or be returned only if the current user has some capabilities enabled.
1317 *
1318 * @return array the list of configs
1319 * @since Moodle 3.5
1320 */
1321 public function get_config_for_external() {
1322 return array();
1323 }
ee7084e9
MG
1324}
1325
1326/**
1327 * Pseudo course format used for the site main page
1328 *
1329 * @package core_course
1330 * @copyright 2012 Marina Glancy
1331 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1332 */
1333class format_site extends format_base {
1334
1335 /**
1336 * Returns the display name of the given section that the course prefers.
1337 *
1338 * @param int|stdClass $section Section object from database or just field section.section
1339 * @return Display name that the course format prefers, e.g. "Topic 2"
1340 */
1341 function get_section_name($section) {
1342 return get_string('site');
76ab3fa1 1343 }
ee7084e9
MG
1344
1345 /**
1346 * For this fake course referring to the whole site, the site homepage is always returned
1347 * regardless of arguments
1348 *
1349 * @param int|stdClass $section
1350 * @param array $options
1351 * @return null|moodle_url
1352 */
1353 public function get_view_url($section, $options = array()) {
68255608 1354 return new moodle_url('/', array('redirect' => 0));
ee7084e9 1355 }
ee7084e9 1356
b5cf83f0
MG
1357 /**
1358 * Returns the list of blocks to be automatically added on the site frontpage when moodle is installed
1359 *
1360 * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT
1361 * each of values is an array of block names (for left and right side columns)
1362 */
1363 public function get_default_blocks() {
1364 return blocks_get_default_site_course_blocks();
1365 }
1366
1367 /**
1368 * Definitions of the additional options that site uses
1369 *
1370 * @param bool $foreditform
1371 * @return array of options
1372 */
1373 public function course_format_options($foreditform = false) {
1374 static $courseformatoptions = false;
1375 if ($courseformatoptions === false) {
1376 $courseformatoptions = array(
1377 'numsections' => array(
1378 'default' => 1,
1379 'type' => PARAM_INT,
1380 ),
1381 );
1382 }
1383 return $courseformatoptions;
1384 }
8341055e
MG
1385
1386 /**
1387 * Returns whether this course format allows the activity to
1388 * have "triple visibility state" - visible always, hidden on course page but available, hidden.
1389 *
1390 * @param stdClass|cm_info $cm course module (may be null if we are displaying a form for adding a module)
1391 * @param stdClass|section_info $section section where this module is located or will be added to
1392 * @return bool
1393 */
1394 public function allow_stealth_module_visibility($cm, $section) {
1395 return true;
1396 }
b5cf83f0 1397}