diff --git a/course/externallib.php b/course/externallib.php index f38953a354c..ddede57b623 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -756,6 +756,26 @@ class core_course_external extends external_api { ); } + /** + * Return array of all editable course custom fields indexed by their shortname + * + * @param \context $context + * @param int $courseid + * @return \core_customfield\field_controller[] + */ + public static function get_editable_customfields(\context $context, int $courseid = 0): array { + $result = []; + + $handler = \core_course\customfield\course_handler::create(); + $handler->set_parent_context($context); + + foreach ($handler->get_editable_fields($courseid) as $field) { + $result[$field->get('shortname')] = $field; + } + + return $result; + } + /** * Returns description of method parameters * @@ -928,8 +948,13 @@ class core_course_external extends external_api { // Custom fields. if (!empty($course['customfields'])) { + $customfields = self::get_editable_customfields($context); foreach ($course['customfields'] as $field) { - $course['customfield_'.$field['shortname']] = $field['value']; + if (array_key_exists($field['shortname'], $customfields)) { + // Ensure we're populating the element form fields correctly. + $controller = \core_customfield\data_controller::create(0, null, $customfields[$field['shortname']]); + $course[$controller->get_form_element_name()] = $field['value']; + } } } @@ -1141,10 +1166,15 @@ class core_course_external extends external_api { } } - // Prepare list of custom fields. + // Custom fields. if (isset($course['customfields'])) { + $customfields = self::get_editable_customfields($context, $course['id']); foreach ($course['customfields'] as $field) { - $course['customfield_' . $field['shortname']] = $field['value']; + if (array_key_exists($field['shortname'], $customfields)) { + // Ensure we're populating the element form fields correctly. + $controller = \core_customfield\data_controller::create(0, null, $customfields[$field['shortname']]); + $course[$controller->get_form_element_name()] = $field['value']; + } } } diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php index 3911a36d977..e71b974c543 100644 --- a/course/tests/externallib_test.php +++ b/course/tests/externallib_test.php @@ -453,10 +453,12 @@ class externallib_test extends externallib_advanced_testcase { // Custom fields. $fieldcategory = self::getDataGenerator()->create_custom_field_category(['name' => 'Other fields']); - $customfield = ['shortname' => 'test', 'name' => 'Custom field', 'type' => 'text', - 'categoryid' => $fieldcategory->get('id'), - 'configdata' => ['visibility' => \core_course\customfield\course_handler::VISIBLETOALL]]; - $field = self::getDataGenerator()->create_custom_field($customfield); + $fieldtext = self::getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), 'name' => 'Text', 'shortname' => 'text', 'type' => 'text', + ]); + $fieldtextarea = self::getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), 'name' => 'Textarea', 'shortname' => 'textarea', 'type' => 'textarea', + ]); // Set the required capabilities by the external function $contextid = context_system::instance()->id; @@ -508,7 +510,10 @@ class externallib_test extends externallib_advanced_testcase { $course4['fullname'] = 'Test course with custom fields'; $course4['shortname'] = 'Testcoursecustomfields'; $course4['categoryid'] = $category->id; - $course4['customfields'] = [['shortname' => $customfield['shortname'], 'value' => 'Test value']]; + $course4['customfields'] = [ + ['shortname' => $fieldtext->get('shortname'), 'value' => 'And I want to tell you so much'], + ['shortname' => $fieldtextarea->get('shortname'), 'value' => 'I love you'], + ]; $courses = array($course4, $course1, $course2, $course3); $createdcourses = core_course_external::create_courses($courses); @@ -580,7 +585,10 @@ class externallib_test extends externallib_advanced_testcase { $handler = core_course\customfield\course_handler::create(); $customfields = $handler->export_instance_data_object($createdcourse['id']); - $this->assertEquals((object)['test' => 'Test value'], $customfields); + $this->assertEquals((object) [ + 'text' => 'And I want to tell you so much', + 'textarea' => '
I love you
', + ], $customfields); } else { throw new moodle_exception('Unexpected shortname'); } @@ -1857,12 +1865,17 @@ class externallib_test extends externallib_advanced_testcase { // Course with custom fields. $fieldcategory = self::getDataGenerator()->create_custom_field_category(['name' => 'Other fields']); - $customfield = ['shortname' => 'test', 'name' => 'Custom field', 'type' => 'text', - 'categoryid' => $fieldcategory->get('id'), - 'configdata' => ['visibility' => \core_course\customfield\course_handler::VISIBLETOALL, 'locked' => 1]]; - $field = self::getDataGenerator()->create_custom_field($customfield); - $originalcourse3 = self::getDataGenerator()->create_course(['customfield_test' => 'Test value']); + $fieldtext = self::getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), 'name' => 'Text', 'shortname' => 'text', 'type' => 'text', 'configdata' => [ + 'locked' => 1, + ], + ]); + $fieldtextarea = self::getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), 'name' => 'Textarea', 'shortname' => 'textarea', 'type' => 'textarea', + ]); + + $originalcourse3 = self::getDataGenerator()->create_course(); self::getDataGenerator()->enrol_user($USER->id, $originalcourse3->id, $roleid); // Course values to be updated. @@ -1895,8 +1908,11 @@ class externallib_test extends externallib_advanced_testcase { $course2['forcetheme'] = 'classic'; $course3['id'] = $originalcourse3->id; - $updatedcustomfieldvalue = ['shortname' => 'test', 'value' => 'Updated test value']; - $course3['customfields'] = [$updatedcustomfieldvalue]; + $course3['customfields'] = [ + ['shortname' => $fieldtext->get('shortname'), 'value' => 'I long to see the sunlight in your hair'], + ['shortname' => $fieldtextarea->get('shortname'), 'value' => 'And tell you time and time again'], + ]; + $courses = array($course1, $course2, $course3); $updatedcoursewarnings = core_course_external::update_courses($courses); @@ -1937,7 +1953,10 @@ class externallib_test extends externallib_advanced_testcase { } $this->assertEquals($course2['enablecompletion'], $courseinfo->enablecompletion); - $this->assertEquals(['test' => null], (array)$customfields); + $this->assertEquals((object) [ + 'text' => null, + 'textarea' => null, + ], $customfields); } else if ($course['id'] == $course1['id']) { $this->assertEquals($course1['fullname'], $courseinfo->fullname); $this->assertEquals($course1['shortname'], $courseinfo->shortname); @@ -1947,9 +1966,15 @@ class externallib_test extends externallib_advanced_testcase { $this->assertEquals(5, course_get_format($course['id'])->get_last_section_number()); $this->assertEquals(0, $courseinfo->newsitems); $this->assertEquals(FORMAT_MOODLE, $courseinfo->summaryformat); - $this->assertEquals(['test' => null], (array)$customfields); + $this->assertEquals((object) [ + 'text' => null, + 'textarea' => null, + ], $customfields); } else if ($course['id'] == $course3['id']) { - $this->assertEquals(['test' => $updatedcustomfieldvalue['value']], (array)$customfields); + $this->assertEquals((object) [ + 'text' => 'I long to see the sunlight in your hair', + 'textarea' => '
And tell you time and time again
', + ], $customfields); } else { throw new moodle_exception('Unexpected shortname'); } @@ -2087,14 +2112,18 @@ class externallib_test extends externallib_advanced_testcase { $this->setUser($user); self::getDataGenerator()->enrol_user($user->id, $course3['id'], $roleid); - $newupdatedcustomfieldvalue = ['shortname' => 'test', 'value' => 'New updated value']; - $course3['customfields'] = [$newupdatedcustomfieldvalue]; + $course3['customfields'] = [ + ['shortname' => 'text', 'value' => 'New updated value'], + ]; core_course_external::update_courses([$course3]); // Custom field was not updated. $customfields = \core_course\customfield\course_handler::create()->export_instance_data_object($course3['id']); - $this->assertEquals(['test' => $updatedcustomfieldvalue['value']], (array)$customfields); + $this->assertEquals((object) [ + 'text' => 'I long to see the sunlight in your hair', + 'textarea' => '
And tell you time and time again
', + ], $customfields); } /** diff --git a/customfield/field/textarea/classes/data_controller.php b/customfield/field/textarea/classes/data_controller.php index 3d52fe15bc4..a72d99c8bd3 100644 --- a/customfield/field/textarea/classes/data_controller.php +++ b/customfield/field/textarea/classes/data_controller.php @@ -88,7 +88,14 @@ class data_controller extends \core_customfield\data_controller { if (!property_exists($datanew, $fieldname)) { return; } + + // Normalise form data, for cases it's come from an external source. $fromform = $datanew->$fieldname; + if (!is_array($fromform)) { + $fromform = ['text' => $fromform]; + $fromform['format'] = $this->get('id') ? $this->get('valueformat') : + $this->get_field()->get_configdata_property('defaultvalueformat'); + } if (!$this->get('id')) { $this->data->set('value', ''); diff --git a/customfield/tests/generator/lib.php b/customfield/tests/generator/lib.php index 06cfe479f97..93a85c6a3d2 100644 --- a/customfield/tests/generator/lib.php +++ b/customfield/tests/generator/lib.php @@ -124,6 +124,7 @@ class core_customfield_generator extends component_generator_base { 'locked' => 0, 'visibility' => 2, 'defaultvalue' => '', + 'defaultvalueformat' => FORMAT_MOODLE, 'displaysize' => 0, 'maxlength' => 0, 'ispassword' => 0,