diff --git a/admin/tool/uploadcourse/classes/course.php b/admin/tool/uploadcourse/classes/course.php index c23c25ffbae..7656ae8b593 100644 --- a/admin/tool/uploadcourse/classes/course.php +++ b/admin/tool/uploadcourse/classes/course.php @@ -693,7 +693,15 @@ class tool_uploadcourse_course { return false; } - // TODO MDL-59259 allow to set course format options for the current course format. + // Add data for course format options. + if (isset($coursedata['format']) || $exists) { + if (isset($coursedata['format'])) { + $courseformat = course_get_format((object)['format' => $coursedata['format']]); + } else { + $courseformat = course_get_format($existingdata); + } + $coursedata += $courseformat->validate_course_format_options($this->rawdata); + } // Special case, 'numsections' is not a course format option any more but still should apply from defaults. if (!$exists || !array_key_exists('numsections', $coursedata)) { diff --git a/admin/tool/uploadcourse/tests/course_test.php b/admin/tool/uploadcourse/tests/course_test.php index f52ec31d8b2..4896658807f 100644 --- a/admin/tool/uploadcourse/tests/course_test.php +++ b/admin/tool/uploadcourse/tests/course_test.php @@ -99,7 +99,8 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $this->assertTrue($co->prepare()); $this->assertFalse($DB->record_exists('course', array('shortname' => 'newcourse'))); $co->proceed(); - $this->assertTrue($DB->record_exists('course', array('shortname' => 'newcourse'))); + $course = $DB->get_record('course', array('shortname' => 'newcourse'), '*', MUST_EXIST); + $this->assertEquals(0, course_get_format($course)->get_course()->coursedisplay); // Try to add a new course, that already exists. $coursecount = $DB->count_records('course', array()); @@ -118,6 +119,16 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $this->assertTrue($co->prepare()); $co->proceed(); $this->assertTrue($DB->record_exists('course', array('shortname' => 'c2'))); + + // Add a new course with non-default course format option. + $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; + $data = array('shortname' => 'c3', 'fullname' => 'C3', 'summary' => 'New c3', 'category' => 1, + 'format' => 'weeks', 'coursedisplay' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data); + $this->assertTrue($co->prepare()); + $co->proceed(); + $course = $DB->get_record('course', array('shortname' => 'c3'), '*', MUST_EXIST); + $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay); } public function test_create_with_sections() { @@ -260,6 +271,16 @@ class tool_uploadcourse_course_testcase extends advanced_testcase { $this->assertTrue($co->prepare()); $co->proceed(); $this->assertEquals('Use this summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); + + // Update course format option. + $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; + $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; + $data = array('shortname' => 'c1', 'coursedisplay' => 1); + $co = new tool_uploadcourse_course($mode, $updatemode, $data); + $this->assertTrue($co->prepare()); + $co->proceed(); + $course = $DB->get_record('course', array('shortname' => 'c1'), '*', MUST_EXIST); + $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay); } public function test_data_saved() { diff --git a/course/format/lib.php b/course/format/lib.php index 045d0499f94..f70371c1137 100644 --- a/course/format/lib.php +++ b/course/format/lib.php @@ -735,6 +735,43 @@ abstract class format_base { return array(); } + /** + * Prepares values of course or section format options before storing them in DB + * + * If an option has invalid value it is not returned + * + * @param array $rawdata associative array of the proposed course/section format options + * @param int|null $sectionid null if it is course format option + * @return array array of options that have valid values + */ + protected function validate_format_options(array $rawdata, int $sectionid = null) : array { + if (!$sectionid) { + $allformatoptions = $this->course_format_options(true); + } else { + $allformatoptions = $this->section_format_options(true); + } + $data = array_intersect_key($rawdata, $allformatoptions); + foreach ($data as $key => $value) { + $option = $allformatoptions[$key] + ['type' => PARAM_RAW, 'element_type' => null, 'element_attributes' => [[]]]; + $data[$key] = clean_param($value, $option['type']); + if ($option['element_type'] === 'select' && !array_key_exists($data[$key], $option['element_attributes'][0])) { + // Value invalid for select element, skip. + unset($data[$key]); + } + } + return $data; + } + + /** + * Validates format options for the course + * + * @param array $data data to insert/update + * @return array array of options that have valid values + */ + public function validate_course_format_options(array $data) : array { + return $this->validate_format_options($data); + } + /** * Updates format options for a course or section * @@ -747,6 +784,7 @@ abstract class format_base { */ protected function update_format_options($data, $sectionid = null) { global $DB; + $data = $this->validate_format_options((array)$data, $sectionid); if (!$sectionid) { $allformatoptions = $this->course_format_options(); $sectionid = 0; @@ -772,7 +810,6 @@ abstract class format_base { 'sectionid' => $sectionid ), '', 'name,id,value'); $changed = $needrebuild = false; - $data = (array)$data; foreach ($defaultoptions as $key => $value) { if (isset($records[$key])) { if (array_key_exists($key, $data) && $records[$key]->value !== $data[$key]) { diff --git a/course/format/upgrade.txt b/course/format/upgrade.txt index 394bf21362b..16a2c668039 100644 --- a/course/format/upgrade.txt +++ b/course/format/upgrade.txt @@ -2,6 +2,13 @@ This files describes API changes for course formats Overview of this plugin type at http://docs.moodle.org/dev/Course_formats +=== 3.6 === +* New method validate_format_options() cleans the values of the course/section format options before inserting them + in the database. Course format options can now be set in tool_uploadcourse and validation of user-submitted data is important. + Note that validate_format_options() is now always called when somebody creates or edits course or section and also + during restore and course upload. Default implementation validates against the definition of the form elements for + format options. + === 3.5 === * Course formats should overwrite get_config_for_external function to return the course format settings viewable by the current user.